1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1、电平标准
根据通讯使用的电平标准不同,串口通讯可分为TTL标准和RS-232标准,如下表: 从图中可以看到,TTL电平标准使用5V表示高电平,使用0V表示低电平。在R232电平标准中,为了增加串口通讯的远距离传输及抗干扰能力,使用的是-15V表示高电平,使用+15V表示低电平。如下图为RS232和TLL电平标准表示同一个信号时的对比。 在电子电路中,一般使用TTL电平进行通讯,而在PC机中则使用RS232电平进行通讯。所以为了使电子设备可以和PC机进行串口通讯,必须对TTL电平和RS232电平的信号进行互相转换。 2、串口协议 串口通讯的英文全称为Serial Communication,这是一种在设备间非常常用的串行通讯方式。 串口通讯的协议,串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备的RXD接口。在串口通讯的协议中,规定了数据包的内容,该内容由起始位、数据位、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。格式如下图: 在数据帧格式中,校验位可以要也可以不要。 一般在串口通信中,空闲状态下,IO口的电平为高电平。 3、串口波特率 串口通讯一般使用的是异步通讯,异步通讯是没有时钟信号的,为了保证两个设备能够正常通讯,必须在两个设备间约定好收发的速率,波特率就是设备的收发速率,波特率表示的是单位时间内收发的bit位,即一个bit的收发时长。比如波特率为9600的设备,那么该设备1S的时间内可以收发9600个bit,发送一个bit的时长位1/9600≈104us。 4、数据帧的起始信号和停止信号 串口通讯的一个数据包是从起始信号开始的,直到停止信号结束。数据包的起始信号由一个逻辑0的数据位表示,而数据包的停止信号可由0.5、1、1.5或2个逻辑1的数据位表示。 有效数据: 在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定位5、6、7或8位。 数据校验: 在有效数据之后,有一个可选的数据校验位,由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程中加上校验位来解决这个问题,校验方法有奇校验、偶校验、0校验、1校验及无校验。 奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个8位长的有效数据位:01101001,此时总共有4个“1”,为达到奇校验的效果,校验位为“1”,最后传输的数据将是8位的有效数据加上1位的校验位总共9位。 偶校验与奇校验要求刚好相反,要求有效数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时有效数据“1”的个数位4,所以偶校验位为“0”。 0校验是不管有效数据中的内容是什么,校验位总为“0”。 1校验是不管有效数据中的内容是什么,校验位总为“1”。 5、UART和USART的区别 UART是指通用异步收发器,UASRT是指通用同步/异步收发器。从名称上可是看出,USART是在UART基础上增加了同步功能,即USART是UART的增强型。 STM32的USART一般做异步通信,即UART功能。 6、USART功能概述 使用USART双向通信至少需要三个脚:GND、RX、TX。 RX:接收数据引脚,通过采样技术来区别数据和噪音,从而恢复数据。 TX:发送数据引脚,当发送器被禁止时,输出引脚恢复到它的IO端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平,也就是说USART的空闲状态的电平时高电平。这里需要注意一点的是,当与设备相连的时候,如果设备断电,这需要将发送器禁止,使TX口输出低电平,否者有可能引起IO口电流倒灌。 TX脚位在单线和智能卡模式里被同时用于数据的发送和接收。 USART总线在发送或接收前应处于空闲状态,即高电平。 一个起始位,起始位为1。 一个数据字,可以使8位数据或9位数据。发送或接收数据的时候,是先发送或接收低位数据。 停止位可设置为0.5、1、1.5、2个停止位,发送或接收停止位说明数据帧发送或接收完成。 使用分数波特率发生器,由12位整数和4位小数组成。 一个状态寄存器USART_SR 数据寄存器USART_DR 一个波特率寄存器USART_BRR,12位表示波特率的整数,4位表示波特率的小数。 一个智能卡模式下的保护时间寄存器USART_GTPR USART的框图如下: 7、STM32的USART波特率配置 STM32的每个串口都有一个独立的波特率寄存器USART_BRR,该寄存器由USART分频器除法因子USARTDIV的整数部分和小数部分组成。bit4~bit15这12位组成了整数部分DIV_Mantissa,bit0~bit3这4个位组成了分数部分DIV_Fraction。 波特率的计数公式 = CLK/(16*USARTDIV)。 CLK是USART的时钟频率,USART2、USART3、USART4、USART5使用的是APB1总线时钟,一般是36MHZ(STM32F103系列);而USART1则使用的是APB2总线时钟,一般是72MHZ(STM32F103系列)。 可以根据需要的波特率的值换算出USARTDIV的值。比如设置波特率为9600,则USARTDIV为: USARTDIV = CLK / (16 * 9600) 如果CLK = 72MHZ,则: USARTDIV = 72000000/(16*9600) = 468.75 将小数部分换算为16进制: DIV_Fraction = 0.75*16 = 12 = 0x0C 将整数部分转为16进制: DIV_Mantissa = 468 = 0x1D4 所以波特率寄存器USART_BRR的值为0x1D4C。 设置波特率时的误差如下图: 注意不要在通信过程中改变波特率寄存器的值。 8、USART中断请求 USART中断请求表: USART中断映像图: 从中断映像图中可以看出,USART的各种中断事件被连接到同一个中断向量,也就是说USART产生的中断都会进入到同一个中断服务函数内。 各种中断事件: 发送期间:发送完成、清除发送、发送数据。 接收期间:空闲总线检测、溢出错误、接收数据寄存器非空、校验错误、LIN断开符号检测、噪音标志(仅在多缓冲器通信)和帧错误(仅在多缓冲器通信)。 如果设置了对应的使能控制位,这些事件就可以产生各自的中断,可以在中断服务函数内通过判断状态寄存器的位来区分是哪个中断。 9、USART寄存器 只说明一些用到的位。 USART_SR状态寄存器: Bit7 TXE位:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,TXE被硬件置位。 Bit6 TC位:当发送完一帧有效数据的时候,TC就会置位。 Bit5 RXNE位:当USART的RDR移位寄存器中的数据被转移到USART_DR寄存器中时,RXNE位被置1,也就是收到数据的时候RXNE位被置1;如果USART_CR1寄存器中的RXNEIE使能,且USART的中断使能,则产生中断,就是所谓的接收中断。RXNE位可以通过对USART_DR寄存器的读取操作来清除,也可以对USART_SR寄存器的bit5写0来清除。 USART_DR数据寄存器: 该寄存器用来发送和接收数据。 USART_BRR波特比率寄存器: 该寄存器用来设置USART的波特率。 USART_CR1控制寄存器: Bit13 UE位:这个位用来使能和停止USART模块,这有UE位被置1的时候,USART才能工作。 Bit12 M位:该位用来定义数据字的长度,当M=0时,数据字的长度为8个bit;当M=1时,数据字的长度为9个bit。 Bit10 PCE位:该位用来控制是否使用校验,当PCE=0时,禁止校验控制;当PCE=1时,使能校验控制。 Bit9 PS位:该位用来选择校验方式,当PS=0时,使用偶校验方式;当PS=1时,使用奇校验。 Bit8 PEIE位:该位用来控制校验错误中断,当PEIE=0时,禁止校验错误产生中断;当PEIE=1时,使能校验错误产生中断。 Bit7 TXEIE位:这个是发送缓冲区空中断使能位,当TXEIE=0时,禁止发送缓冲区空时产生中断;当TXEIE=1时,使能发送缓冲区空时产生中断。 Bit6 TCIE位:这个是发送完成 中断使能,当TCIE=0时,禁止发送完成产生中断;当TCIE=1时,使能发送完成产生中断。 Bit5 RXNEIE位:这个是接收缓冲区非空中断使能,当RXNEIE=0时,禁止接收完成时产生中断;当RXNEIE=1时,使能接收完成时产生中断。 Bit4 IDLEIE位:这个是IDLE总线空闲中断使能位,当IDLEIE=0时,禁止检测到总线空闲时产生中断;当IDLEIE=1时,使能检测到总线空闲时产生中断。 Bit3 TE位:这个是发送使能位,当TE=0时,禁止USART发送数据;当TE=1时,使能USART发送数据。 Bit2 RE位:这个是接收使能位,当RE=0时,禁止USART接收数据;当RE=1时,使能USART接收数据。 这里主要区分发送缓冲区空和发送完成这两个点,发送缓冲器空是指USART_DR寄存器的数值被硬件转移到以为寄存器的时候,也就是说要发送的数值进入移位寄存器的时候,发送缓冲器空这个条件就会成立。而发送完成是指移位寄存器里的数据发送完成。 当将一个数据写入USART_DR寄存器的时候,硬件将USART_DR寄存器的值送入移位寄存器,送完之后会置位USART_SR寄存器的bit7 TXE位,而当移位寄存器里的数值发送完成之后会置位USART_SR寄存器的bit6 TC位。 USART_CR2控制寄存器: Bit12~Bit13 STOP位:这个是停止位长度的选择位,当STOP=00时,使用1个停止位;当STOP=01时,使用0.5个停止位;当STOP=10时,使用2个停止位;当STOP=11时,使用1.5个停止位; 需要注意的是UART4和UART5不能使用0.5和1.5个停止位。 10、HAL库操作USART 在工程之中添加stm32f1xx_hal_uart.c和stm32f1xx_hal_uart.h文件。 初始化代码如下: UART_HandleTypeDef UART_Handler; 2 3 uint8_t aRxBuffer; 4 5 void USART_Init(void) 6 { 7 8 UART_Handler.Instance = USART1; 9 UART_Handler.Init.BaudRate = 9600;10 UART_Handler.Init.Mode = UART_MODE_TX_RX;11 UART_Handler.Init.StopBits = UART_STOPBITS_1;12 UART_Handler.Init.WordLength = UART_WORDLENGTH_8B;13 UART_Handler.Init.Parity = UART_PARITY_NONE;14 UART_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;15 HAL_UART_Init(&UART_Handler);16 17 //HAL_UART_Receive_IT(&UART_Handler,aRxBuffer,2);18 __HAL_UART_ENABLE_IT(&UART_Handler, UART_IT_RXNE);19 20 HAL_NVIC_SetPriority(USART1_IRQn,2,1);21 HAL_NVIC_EnableIRQ(USART1_IRQn);22 23 } 使用HAL_UART_Init()函数初始化USART设备。 从初始化代码内,可以看到,需要选择初始化的USART、波特率、USART的模式(接收和发送)、停止位长度的选择、数据的长度选择、校验的选择、硬件控制流的选择。还需要设置USART的时钟和脚位,但是HAL_UART_Init()函数内会调用USART的时钟和脚位的初始化回调函数,可以在回调函数内设置脚位和时钟。 初始化完USART之后,打开USART的接收中断,由于HAL库的接收程序比较复杂,这里直接调用宏__HAL_UART_ENABLE_IT(&UART_Handler, UART_IT_RXNE)来打开USART的接收中断。 IO和RCC初始化函数如下: 1 void HAL_UART_MspInit(UART_HandleTypeDef *husart) 2 { 3 GPIO_InitTypeDef GPIO_InitStruct; 4 5 __HAL_RCC_GPIOA_CLK_ENABLE(); 6 __HAL_RCC_USART1_CLK_ENABLE(); 7 8 GPIO_InitStruct.Pin = GPIO_PIN_9; 9 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 10 GPIO_InitStruct.Pull = GPIO_NOPULL; 11 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 12 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 13 14 GPIO_InitStruct.Pin = GPIO_PIN_10; 15 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 16 GPIO_InitStruct.Pull = GPIO_NOPULL; 17 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 18 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 19 20 } 这里注意的是RX脚,既可以设置成浮空输入模式也可以设置成复用输入模式,这两个是一样的。 中断处理函数如下: void USART1_IRQHandler(void) 2 { 3 //HAL_UART_IRQHandler(&UART_Handler); 4 5 if(__HAL_UART_GET_FLAG(&UART_Handler,UART_FLAG_RXNE)) 6 { 7 aRxBuffer = UART_Handler.Instance->DR; 8 HAL_UART_Transmit(&UART_Handler,&aRxBuffer,1,1000); 9 } 10 } 由于HAL库的中断服务处理比较繁琐,这里直接读取USART的中断标志位来处理接收中断。 收到数据到,通过读取USART_DR寄存器的值来获取接收到的数值,这里将接收到的数据再发送出去。 HAL库中断处理函数说明: 在HAL库中断处理中,进入中断处理函数之后会调用HAL_UART_IRQHandler()函数,在HAL_UART_IRQHandler()函数内判断是那种类型的中断,然后去执行响应的操作。比如接收到数据后,会在HAL_UART_IRQHandler()函数内调用UART_Receive_IT()函数。 这里需要注意一个问题,在UART_Receive_IT()函数中,接收完成后会清除掉接收中断的使能位,实际在用HAL库来处理中断的时候,接收中断使能位莫名会被清掉。 在UART_Receive_IT()函数中会调用接收数据的回调函数HAL_UART_RxCpltCallback()来处理数据。 使用HAL_UART_Receive_IT(&UART_Handler,aRxBuffer,len)函数来接收数据的时候,如果数据长度不为1,则接收到1个数据的时候,不会进入到HAL_UART_RxCpltCallback()函数中,只有收到实际设置的数据长度时,才会进入HAL_UART_RxCpltCallback()函数。通过进入UART_Receive_IT()函数查看代码的时候,会发现,当接收完实际设置的数据长度时,会清除掉接收中断的使能位,这里需要小心,防止收到一次数据之后,不能再进入接收中断。 添加支持printf()函数的代码: 1 //加入以下代码,支持printf函数,而不需要选择use MicroLIB 2 #pragma import(__use_no_semihosting) 3 //标准库需要的支持函数 4 struct __FILE 5 { 6 int handle; 7 8 }; 9 10 FILE __stdout; 11 //定义_sys_exit()以避免使用半主机模式 12 void _sys_exit(int x) 13 { 14 x = x; 15 } 16 //重定义fputc函数 17 int fputc(int ch, FILE *f)18 { 19 while(__HAL_UART_GET_FLAG(&UART_Handler,UART_FLAG_TC) == RESET){}; 20 21 UART_Handler.Instance->DR = (uint8_t) ch;22 23 return ch;24 } 加上以上代码后就可以使用printf()函数发送UART数据了,比如printf("hello world!")。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 23:04 , Processed in 0.968173 second(s), Total 76, Slave 60 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号