0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32的串口实验(寄存器操作版本)

dytfki8u8yql 来源:电子技术控 2023-04-23 10:07 次阅读
USART—通用同步异步收发接收器,是一个串行通信设备,可以和外部设备进行灵活的全双工数据交换,有别于USART还有一个UART(在原来的基础上裁剪掉了同步通信功能(时钟同步)),串行通信一般是以帧格式传输数据,一帧一帧的传。 协议层:串口通信的一个数据包包含从起始信号开始,直到停止信号的结束起始信号:一个逻辑0数据位表示。停止信号:0.5,1,1.5或2个逻辑1的数据位表示。0.5个停止位:智能卡模式下的接收数据时使用。1个停止位:停止位的默认数值1.5个停止位:智能卡模式下的手法数据和接收数据时使用2个停止位:常规USART模式,单线模式以及调制解调器的模式。有效数据的基本长度被约定为5,6,7,8.奇偶检验(设置USART-CR1 的PS位)偶检验:数据=00110101,里面数据1的个数位为偶数位,检验位置“0”,当数据检验和偶数相同的时候,证明没有出错,反之则错误奇检验:数据 = 01110101,里面数据1的个数为奇检位,检验位置“1”,当数据检验和奇数相同,则证明没有出错,反之错误。当然也会存在同时两个位一块出现错误,导致无法判断是否位奇偶检验的错误,但发生的概率很低。 下面这张图需要重点理解下面是对代码的理解:首先先看这个图,,可以看出USART_RX_STA类似与一个16位的寄存器,前14位存储的是数据,后面两个分别检测0X0D和0X0A。接下里分析:

	void uart_init(u32 pclk2,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分 mantissa<<=4; mantissa+=fraction; RCC->APB2ENR|=1<<2; //使能PORTA口时钟 RCC->APB2ENR|=1<<14; //使能串口时钟 GPIOA->CRH&=0XFFFFF00F;//IO状态设置 GPIOA->CRH|=0X000008B0;//IO状态设置 RCC->APB2RSTR|=1<<14; //复位串口1 RCC->APB2RSTR&=~(1<<14);//停止复位 //波特率设置 USART1->BRR=mantissa; // 波特率设置 USART1->CR1|=0X200C; //1位停止,无校验位. #if EN_USART1_RX //如果使能了接收 //使能接收中断 USART1->CR1|=1<<5; //接收缓冲区非空中断使能 MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级 #endif }temp=(float)(pclk2*1000000)/(bound*16);这是一个计算公式,因为使能的是串口1,而串口1是在APB2ENR寄存器里面(其余串口均在寄存器APB1ENR里面),因为APB2的频率一般位72M,而APB1的频率一般位36M。所以这里的pclk2为72M,而bound是你需要设置的波特率。

	USARTX-BRR:前四位为小数部分 ,后12位是整数部分,假设算出来的mantissa = 39.5,小数部分相当于把1分成了16份,所以相当于把0.5*16转化为二进制存入。

	mantissa = temp的作用仅仅是:为了接下来将小数部分求出来 fraction=(temp-mantissa)*16; //得到小数部分 mantissa<<=4;这两行代码是为将十进制的整数部分和小数部分,分别转化为16进制。然后存入到波特率寄存器里面。紧接着使能串口1和PORTA时钟(串口一对应的IO口是PA9,PA10,需要拿跳帽连接在一起).然后将IO口置零,然后分别进行设置成一个输入一个输出,

	USART1->CR1|=0X200C; 设置成使能串口8个字长1个停止位(USART_CR2中[13:12]默认为“0”) MY_NVIC_Init(3,3,USART1_IRQn,2)将其分在组2里面,此时的抢占优先级:响应优先级为 = 2:2,即(00-11)四种情况,而3:3的安排选择了组2优先级最小的一种情况。这样可以先执行上面的波特率赋值,以及串口使能等等操作,最后再进行这行代码运行。接下来看下一部分:

	u16 USART_RX_STA=0; //接收状态标记 void USART1_IRQHandler(void) { u8 res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif if(USART1->SR&(1<<5)) //接收到数据 { res=USART1->DR; if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0x3fff]=res; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } } } }起始阶段: USART_RX_STA=0,对接受状态的标记。先通过状态寄存器SR的RXNE是否为1,是1则接收到了数据,反之则没有。紧接这定义一个res变量来接收从数据寄存器的一个字节,然后此时USART_RX_STA为0,与0X8000进行&运算,结果为0,则未接受到,接着继续进行判断,0X4000进行与运算,看是否为0,也是判断是否接受道路0X0D,如果没有接受到,则将这个res变量存放在数组里面,此时的USART_RX_STA为 0 与0X3fff进行&运算,大家算算会发现,因为他的前14位是数据位,所以你会发现第一个变量就会存放在BUF[0]里面,大概逻辑是这样的:所以每个字节都会被存放到具体的数组位上 。if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收当数组越界的时候,则会重新开始。接下来就会一直循环,当数据位存满后,接下来res里面接受的就是0X0D,先和上面一样判断USART_RX_STA是否接受到了0X0A和0X0D。接着执行:

	if(res==0x0d)USART_RX_STA|=0x4000;将USART_RX_STA的第十五位变为1,,接下来进行下一次循环,这一次res接受到的值为0X0A,然后进行判断进入到

	if(USART_RX_STA&0x4000)//接收到了0x0d { if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 }所以执行USART_RX_STA|=0x8000,使得USART_RX_STA的第十六位变为1。接下来看主函数部分:

	int main(void) { u8 t; u8 len; u16 times=0; Stm32_Clock_Init(9); //系统时钟设置 delay_init(72); //延时初始化 uart_init(72,9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 while(1) { if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 printf(" 您发送的消息为: "); for(t=0;tDR=USART_RX_BUF[t]; while((USART1->SR&0X40)==0);//等待发送结束 } printf(" ");//插入换行 USART_RX_STA=0; }else { times++; if(times%5000==0) { printf(" ALIENTEK MiniSTM32开发板 串口实验 "); printf("正点原子@ALIENTEK "); } if(times%200==0)printf("请输入数据,以回车键结束 "); if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行. delay_ms(10); } } }if(USART_RX_STA&0x8000) 判断是否接收到了0X0Alen=USART_RX_STA&0x3fff;举个简单的例子此时USART_RX_STA为1100000000000011和0X3fff进行&运算,得到的结果是3,自然就表示了当前数组的大小。最后阶段,重点理解以下两行代码:

	USART1->DR=USART_RX_BUF[t]; while((USART1->SR&0X40)==0);//等待发送结束分析如下:将每个组内的信息存入到数据寄存器,此时数据寄存器将数据给TDR,发送信息的时候,是一位一位发送的,每一数据帧都有起始位,数据位,以及停止位,当检测到数据寄存器的细信息发送完了(完全给了TDR),此时状态寄存器的TXE便变为1,当检测到TXE为1后,TC也会变为1(系统自动进行)。所以第二行才会检测这个状态寄存器的第6位是否为1来判断是否发送成功了这个字节。由此推出,直接判断TXE也可以判断发送是否完成所以代码可以改为:

	for(t=0;tDR=USART_RX_BUF[t]; while((USART1->SR&0X80)==0);//等待发送结束
		


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接收器
    +关注

    关注

    14

    文章

    2368

    浏览量

    71159
  • STM32
    +关注

    关注

    2251

    文章

    10731

    浏览量

    350597
  • 通信设备
    +关注

    关注

    3

    文章

    300

    浏览量

    31852

原文标题:老工程师:STM32的串口实验(寄存器操作版本)

文章出处:【微信号:电子技术控,微信公众号:电子技术控】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    stm32标准例程-寄存器

    stm32标准例程-寄存器版本的源代码,57个实验例程,从跑马灯到操作系统,全方位学习stm32
    发表于 11-26 16:17 0次下载

    ALIENTEK_MINISTM32_实验3_串口实验

    ALIENTEK MINISTM32 实验3 串口实验,很好的资料,快来学习吧
    发表于 02-18 14:58 9次下载

    如何通过STM32串口实现简易脱机编程

    如何通过STM32串口实现简易脱机编程如何通过STM32串口实现简易脱机编程如何通过
    发表于 04-25 09:38 59次下载

    STM32单片机不完全手册之寄存器版本

    STM32单片机不完全手册之寄存器版本
    发表于 07-31 16:10 0次下载

    STM32F1开发指南-寄存器版本_V3.3.pdf(上)

    STM32F1开发指南-寄存器版本_V3.3.pdf(上)
    发表于 09-28 09:29 0次下载

    STM32F1开发指南-寄存器版本_V3.3pdf(下)

    STM32F1开发指南-寄存器版本_V3.3pdf(下)
    发表于 09-28 09:31 0次下载

    STM32寄存器实现流水灯效果

    一、实验原理(一)寄存器地址查找STM32给不同的寄存器分配了不同的地址在《STM32中文参考手册_V10》的第28页,有不同
    发表于 12-07 10:06 2次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>寄存器</b>实现流水灯效果

    STM32寄存器实现流水灯效果

    一、实验原理(一)寄存器地址查找STM32给不同的寄存器分配了不同的地址在《STM32中文参考手册_V10》的第28页,有不同
    发表于 12-07 10:21 8次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>寄存器</b>实现流水灯效果

    STM32寄存器版本】实例之串口通讯

    以我现在的水平还啥都不了解,所以这次主要说的就是通过USB串口和电脑通信**串口配置**:详细配置可以参考STM32开发指南寄存器版本的5.
    发表于 12-08 17:36 0次下载
    【<b class='flag-5'>STM32</b>—<b class='flag-5'>寄存器</b><b class='flag-5'>版本</b>】实例之<b class='flag-5'>串口</b>通讯

    STM32】基于cubemx+HAL库的串口实验(一)

    stm32串口实验一、实验前准备二、具体项目代码项目1:printf重定向实验,轮询方式通信重定向:轮询方式:中断方式:项目2:中断方式的串口
    发表于 12-09 13:06 3次下载
    【<b class='flag-5'>STM32</b>】基于cubemx+HAL库的<b class='flag-5'>串口实验</b>(一)

    STM32的USART串口通讯程序

    文章目录文章目录文章目录寄存器与固态库一、了解串口通信及准备工作1.串口通信简介2.STM32 的 USART 简介3.实验环境二、USAR
    发表于 12-16 16:57 10次下载
    <b class='flag-5'>STM32</b>的USART<b class='flag-5'>串口</b>通讯程序

    STM32串口通信相关寄存器和中断回调函数

    STM32串口通信相关寄存器状态寄存器 (USART_SR)数据寄存器 (USART_DR)波特率寄存器
    发表于 12-28 19:11 7次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b>通信相关<b class='flag-5'>寄存器</b>和中断回调函数

    2021-04-17 STM32串口寄存器库函数配置

    STM32串口寄存器库函数配置方法STM32常用寄存器和库函数串口配置一般步骤(
    发表于 12-28 19:13 7次下载
    2021-04-17  <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>寄存器</b>库函数配置

    STM32寄存器操作

    STM32寄存器操作在使用STM32单片机编程时一般都用ST给的库函数编程,库函数编程的底层就是对单片机寄存器
    发表于 01-13 15:43 19次下载
    <b class='flag-5'>STM32</b>的<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    STM32F407-双串口实验

    STM32F407-双串口实验,程序将串口1和串口2全部调通,可同时使用
    发表于 06-13 15:06 29次下载