STM32串口USARTSTM32串行USART **STM32串行USART**一、USARTX (串行端口)二、UART配置步骤(启用、初始化)三、UART配置步骤
一. USARTX (串行端口)。
通用异步串行数据码(usart )提供了一种灵活的方法,用于与使用行业标准NR异步串行数据格式的外部设备进行全双工数据交换。 USART利用分数波特率发生器提供大范围的波特率选择,支持同步单向通信和半双工单线通信。
STM32固件库使用外围设备的主要思路
在STM32中,外围设备的配置思路比较固定。 首先是使能相关的时钟。 另一方面,是设备自身的时钟。 另一方面,如果设备通过IO端口输出,则还需要启用IO端口的时钟。如果最后对应的IO端口是多路复用IO端口,则还必须启用启用启用AFIO的时钟。
接下来,配置GPIO。 GPIO的各属性在硬件手册的AFIO章中有详细规定,很简单。
接下来,如果相关设备需要使用中断功能,则需要设置中断优先级,如下文详细所述。
接下来,设置外围设备的相关属性。 某些设备需要使用中断方式时,需要启用对应设备的中断,然后再启用相关设备。
最后,如果设备使用了中断功能,则必须填写相应的中断服务程序,并在服务程序中进行相应的操作。
二、UART配置步骤(使能、初始化) 2.1、开启时钟
由于UART的TX、RX和AFIO悬挂在APB2桥上,因此使用固件库函数RCC_APB2PeriphClockCmd ()进行初始化。 UARTx必须根据情况考虑,因为对于UART1,UARTx被挂在APB2桥上,所以用RCC_APB2PeriphClockCmd ()初始化,其馀的UART2~5全部挂在APB1上。
RCC _ AP B2 periphclockcmd (RCC _ AP B2 per iph _ gpioa|RCC _ AP B2 per iph _ usar t1,ENABLE ); ` 2.2、GPIO初始化
对于TX端子,GPIO_Mode字段被设定为GPIO_Mode_AF_PP (推挽输出的复用),并且GPIO_InitTypeDef包括GPIO的属性GPIO_Mode字段设置为GPIO_Mode_IN_FLOATING (浮动输入),因此不需要设置切换速率。 最后,在GPIO_Init ()中启用IO端口。
GPIO设置的实例代码如下所示。
gpio _ inittypedefgpio _ init structure;
//usart1tx(pa.09 ) gpio _ init structure.gpio _ pin=gpio _ pin _ 9; gpio _ init structure.gpio _ speed=gpio _ speed _ 50m Hz; gpio _ init structure.gpio _ mode=gpio _ mode _ af _ PP; gpio_init(gpioa,GPIO_InitStructure ); //usarT1rx(pa.10 ) gpio _ init structure.gpio _ pin=gpio _ pin _ 10; gpio _ init structure.gpio _ speed=gpio _ speed _ 50m Hz; gpio _ init structure.gpio _ mode=gpio _ mode _ in _ floating; gpio_init(gpioa,GPIO_InitStructure ); 2.3、配置UART相关属性
结构USART_InitTypeDef确定。 URT模式字段如下
USART_BaudRate :波特率取决于特定的设备
USART_WordLength :字长
USART_StopBits :停止位
USART_Parity :检查方式
USART_HardwareFlowControl :硬件流控制
USART_Mode :单/双工
最后设置。 实例代码:
//USART1配置usart _ inittypedefusart _ init structure; usart _ init structure.usart _ baudrate=9600; usart _ init structure.usart _ word length=usart _ word length _ 8b; usart _ init structure.usart _ stop bits=usart _ stop bits _ 1; usart _ init structure.usart _ parity=usart _ parity _ no; usart _ init structure.usart _ hardware flow control=usart _ hardware flow control _ none; usart _ init structure.usart _ mode=usart _ mode _ tx|usart _ mode
_Rx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);别忘了最后要使用USART_Cmd()来启动设备UART1。
2.4、重定向print()函数。
最后通过主函数直接输出即可。
int main(void){ // USART1 config 9600 8-N-1 USART1_Config(); printf("hello world!");} 三、UART的配置步骤(中断方式)打开时钟、GPIO初始化、配置UART相关属性、重定向print()函数 与上面的相同。
3.1、中断优先级的配置
这是STM32比较奇怪的地方,在只有一个中断的情况下,仍然需要配置优先级,其作用是使能某条中断的触发通道。STM32的中断有至多两个层次,分别是先占优先级和从优先级,而整个优先级设置参数的长度为4位,因此需要首先划分先占优先级位数和从优先级位数,通过NVIC_PriorityGroupConfig()实现;
特定设备的中断优先级NVIC的属性包含在结构体NVIC_InitTypeDef中,其中字段NVIC_IRQChannel包含了设备的中断向量,保存在启动代码中;字段NVIC_IRQChannelPreemptionPriority为主优先级,NVIC_IRQChannelSubPriority为从优先级,取值的范围应根据位数划分的情况而定;最后NVIC_IRQChannelCmd字段是是否使能,一般定位ENABLE。最后通过NVIC_Init()来使能这一中断向量。实例代码如下:
3.2、中断的服务程序的设计
目前使用了UART的两个中断USART_IT_RXNE(接收缓存补空中断)和USART_IT_TXE(发送缓存空中断),前一个中断保证了一旦有数据接收到就进入中断以接收特定长度的数据,后一个中断表示一旦发完一个数据就进入中断函数,保证连续发送一段数据。一个设备的所有中断都包含在一个中断服务程序中,因此必须首先分清楚这次响应的是哪一个中断,使用USART_GetITStatus()函数确定;采用USART_ReceiveData()函数接收一个字节数据,采用USART_SendData()函数发送一个字节数据,当关闭中断时采用USART_ITConfig()失能响应的中断。实例程序:
3.3、接收数据函数:
//重定向scanf函数到USART1int fgetc(FILE *f){ /*等待串口1输入数据*/ while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(USART1);} 四、STM32串口在首次发送字符的时候,首字符丢失解决办法网上关于发送字符的代码大多如下:
USART_SendData(USART1, (uint8_t)ch);
while( USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
其实咋一看是说的通的,但是在仔细看手册的时候发现 TC 和 TXE 标志位在复位的时候被置1 ,这样第一次while循环就是没有用的。这样导致了首次第一个字符还没有被输出,就被后面的字符覆盖掉,造成实际看到的丢失现象。解决办法就很简单:在前面加上一句 USART1->SR;
具体代码如下:
USART1->SR;
USART_SendData(USART1, (uint8_t)ch);
while( USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
下面我来说说原因: 第一句读取SR寄存器,第二句写DR寄存器 刚好清除了TC标志位 。第一次while循环就起作用了。
也可将USART1->SR;替换为USART_GetFlagStatus(USART1, USART_FLAG_TC)
串口2、3的配置与串口1配置同理将其的需要使能的引脚和中断函数名称修改即可,插上线即可使用。
接线:将单片机PB2、PB3引脚使用杜邦线与烧录器(我使用DAP)的TX、RX相连,有一点需要注意的是,发送应与接受相连,即单片机的TX与烧录器的RX相接。
中断函数的配置:
void USART2_IRQHandler(void) //串口2中断服务程序{u8 Res2;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) {USART_ClearITPendingBit(USART2,USART_IT_RXNE);Res2 =USART_ReceiveData(USART2);//读取接收到的数据 USART_SendData(USART2,Res2); }}