STM32最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持LIN 、支持调制解调器操作、智能卡协议和IrDA SIR ENDEC 规范(仅串口3 支持)、具有DMA等。使用USART时,stm32的I/O口经RS232电平转换电路 和电脑的串口连接。
串口通信虽然在如今的电脑上使用的越来越少,因为其在通信速率,距离已经不适应pc的要求,取而代之的是USB口。但是在嵌入式领域,USART仍然广泛运用着。
使能串口时钟,设置相应的I/O口模式,配置波特率、数据位长度、奇偶校验位等信息。
1、串口时钟使能
串口作为STM32的一个外设,其时钟有外设时钟使能寄存器控制,这里我们使用的串口1是在APBENR寄存器的第14位,APB2ENR寄存器各位描述如下:
2、串口复位
当外设出现异常的时候可以通过复位寄存器里面对应的位进行复位设置,重新配置这个外设使其重新工作,一般在配置外设的时候都会先执行复位该外设的操作,串口1的复位时通过设置APB2RSTR寄存器的第14位进行设置的,APB2RSTR各位描述:
复位操作:向第14位写1复位串口,写0结束复位,其他串口复位位在APB1RSTR,操作类似。
3、串口波特率设置
每个串口都有一个独立的波特率寄存器USART_BRR,通过对这个寄存器的配置以设置不同的波特率,寄存器描述如下:
实际上这个寄存器配置的是波特比率的分频触发因子的值,波特率是一秒钟通过的字符,而波特比率是一秒钟通过的二进制位数,所以设置了波特率需要经过一段算法处理 ,得出特定时钟下,实现这个波特率的,时钟分频值。
4、串口控制
STM32的每个串口都有3个控制寄存器USART_CR1~3,串口的许多配置都是通过这三个寄存器设置的,这里我们主要用到的是USART_CR1就可以实现基本功能乐儿。寄存器描述如下:
该寄存器的高18位没有用到,低14位用于串口的功能设置:
UE 串口使能位 (USART enable)
M 字节选择位, 0:一个起始位,8个数据位,n个停止位 1:一个起始位,9个数据位,n个停止位。 n停止位的个数是根据USART_CR2的 [13:12]设置的,默认为0.
PCE 校验使能位
PS 校验选择 0为偶校验 1为奇校验
TXIE 发送缓冲区空中断使能位,该位设置为1时,USART_SR中TXE为为1时将产生串口中断
TCIE 发送完成中断使能位,为1时,USART_SR中的TC为1时将产生串口中断
RXNEIE 接收缓冲区非空中断 为1时,USART_SR中的ORE或RXNE为1时,产生串口中断
RE 接收使能位,开启串口接收功能
TE 发送使能位,开启串口发送功能
(STM32参考手册542页)
5、数据的发送和接收
STM32的数据发送和接收是通过数据寄存器USART_DR来实现的,这事一个双寄存器,包含TDR和RDR,写入数据时,串口自动发送,接收数据时,也是存在寄存器内,寄存器描述如下:
虽然是32位寄存器,但是只使用了低9位(DR[9:0]),其他位保留,DR[8:0]为串口数据包含了发送和接收数据
当使能校验位(USART_CR1的 PCE置位时)的时候,写入MSB(数据长度后一位)会写入校验位发送或接收
6、串口状态
串口的状态时通过寄存区USART_SR读取,各位描述如下:
主要的状态位是第5、6位RXNE和TC。
RXNE (读取寄存器数据非空位)为1时,表示有数据接收到了,可以读取USART_DR,通过读取USART_DR可以使该为清0,也可以直接写0,直接清除。
TC (发送完成位) 置位时,表示USART_DR中的数据发送完成,如果设置了这个位的中断,产生中断,两种清零方式1、读USART_SR,写USART_DR 2、直接写0
(具体串口通信可以见《STM32参考手册》516~548)
stm32串口1是在PA9(RXD)、PA10(TXD),首先在电路板上连接正确电路,然后进行软件设计。
USART.C
#include "sys.h" #include "usart.h" //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; /* Whatever you require here. If the only file you are using is */ /* standard output using printf() for debugging, no file handling */ /* is required. */ }; /* FILE is typedef’ d in stdio.h. */ FILE __stdout; //定义_sys_exit()以避免使用半主机模式 _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch; } #endif //end ////////////////////////////////////////////////////////////////// #ifdef EN_USART1_RX //如果使能了接收 //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART_RX_BUF[64]; //接收缓冲,最大64个字节. //接收状态 //bit7,接收完成标志 //bit6,接收到0x0d //bit5~0,接收到的有效字节数目 u8 USART_RX_STA=0; //接收状态标记 void USART1_IRQHandler(void) { u8 res; if(USART1->SR&(1<<5))//接收到数据 { res=USART1->DR; if((USART_RX_STA&0x80)==0)//接收未完成 { if(USART_RX_STA&0x40)//接收到了0x0d { if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x80; //接收完成了 }else //还没收到0X0D { if(res==0x0d)USART_RX_STA|=0x40; else { USART_RX_BUF[USART_RX_STA&0X3F]=res; USART_RX_STA++; if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } } #endif //初始化IO 串口1 //pclk2:PCLK2时钟频率(Mhz) //bound:波特率 //CHECK OK //091209 void uart_init(u32 pclk2,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk2*1000000)/(bound*16);// //得到USART 分频除法因子(每个字符16位,乘16得到每秒通过的字符数) mantissa=temp; //得到BRR[15:4]整数部分 fraction=(temp-mantissa)*16; //得到BRR[3:0]小数部分 mantissa<<=4; mantissa+=fraction; //拼接整数和小数部分 RCC->APB2ENR|=1<<2; //使能PORTA口时钟 RCC->APB2ENR|=1<<14; //使能串口时钟 GPIOA->CRH&=0XFFFFF00F; GPIOA->CRH|=0X000008B0;//IO状态设置 RCC->APB2RSTR|=1<<14; //复位串口1 RCC->APB2RSTR&=~(1<<14);//停止复位 //波特率设置 USART1->BRR=mantissa; // 波特率设置 USART1->CR1|=0X200C; //1位停止,无校验位,无停止位 #ifdef EN_USART1_RX //如果使能了接收 //使能接收中断 USART1->CR1|=1<<8; //PE中断使能 USART1->CR1|=1<<5; //接收缓冲区非空中断使能 MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级 #endif }
//main.c
#include <stm32f10x_lib.h> #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "key.h" 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&0x80) { len=USART_RX_STA&0x3f;//得到此次接收到的数据长度 printf(" 您发送的消息为: "); for(t=0;t<len;t++) { USART1->DR=USART_RX_BUF[t]; while((USART1->SR&0X40)==0);//等待发送结束 } printf(" ");//插入换行 USART_RX_STA=0; }else { times++; if(times%200==0)printf("请输入数据,以回车键结束 "); if(times%30==0)LED0=!LED0;//闪烁 LED ,提示系统正在运行. delay_ms(10); } } }
项目文件下载:PROJ5