stm32串口的使用过程:
1.使能串口时钟,同时使能串口对应的GPIO的时钟;
2.设置串口引脚的输入输出模式、速率,并初始化GPIO引脚;
3.对于需要接收数据的串口,配置其中断,并使能;
4.设置串口的波特率、数据位、停止位、奇偶校验位、流控方式、收发模式;
5.初始化串口;
6.开串口接收中断;
7.使能串口;
8.编写串口中断服务函数;
9.发送数据
补充:STM32中与串口相关的寄存器主要是状态寄存器SR和数据寄存器寄存器DR。
附图如下:
状态寄存器比较重要的两位是第六位RXNE和第七位TC,使用方法USARTx->SR。
TC:发送完成 (Transmission complete)
当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。如果USART_CR1中的
TCIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。TC
位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。
0:发送还未完成;
1:发送完成。
RXNE:读数据寄存器非空 (Read data register not empty)
当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果
USART_CR1寄存器中的RXNEIE为1,则产生中断。对USART_DR的读操作可以将该位清
零。RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。
0:数据没有收到;
1:收到数据,可以读出。
所以常用SR的第六位RXNE来判断是否接收到数据,若接收到数据,就将数据从DR中读取出来,以便DR接收下个数据。
DR[8:0]:数据值 (Data value)
包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收
用(RDR),该寄存器兼具读和写的功能。TDR寄存器提供了内部总线和输出移位寄存器之间的
并行接口(参见图248)。RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。
当使能校验位(USART_CR1中PCE位被置位)进行发送时,写到MSB的值(根据数据的长度不
同,MSB是第7位或者第8位)会被后来的校验位该取代。
当使能校验位进行接收时,读到的MSB位是接收到的校验位。
代码如下:
//定义初始化变量GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;//使能串口2的时钟和GPIOA的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//PA2-TX,PA3-RXRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//配置串口对应引脚的收发模式//USART2_RX GPIOA.3初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);/初始化GPIOA.3 //USART2_TX GPIOA.2初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2 //注意:此处TX和RX引脚都要配置,否则可能无法通信//USART2 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式//初始化USART2USART_Init(USART2, &USART_InitStructure);//开启USART2接收中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能串口2USART_Cmd(USART2, ENABLE); //编写USART2的中断服务函数void USART2_IRQHandler(void) {u8 Res;USART_PRINTF_FLAG=2;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断,判断读寄存器是否为空{Res =USART_ReceiveData(USART2); //读取接收到的数据if((USART2_RX_STA&0x8000)==0)//接收未完成{if(USART2_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART2_RX_STA=0;//接收错误重新开始else {if(crc_check(USART2_RX_BUF,17))USART2_RX_STA|=0x8000; //接收完成elseUSART2_RX_STA=0;//接受错误,重新开始}}else //未接收到0x0d{ if(Res==0x0d)USART2_RX_STA|=0x4000;else{USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;USART2_RX_STA++;if(USART2_RX_STA>(USART_REC_LEN-1))USART2_RX_STA=0;} }} } } //注:此处参考了正点原子所提供的源码,根据自己的需要对接收完成的判断进行了修改//发送数据USART_SendData(UART4, USART2_TX_BUF[t]);//向UART4发送数据while(USART_GetFlagStatus(UART4,USART_FLAG_TC)!=SET);//等待发送结束//注while语句必须存在,否则可能出现接收字符不完整的情况,且USART_SendData一次只能发送一个数据,对于数组需要用循环的方式进行发送//补充:如何用printf进行发送//参照正点原子,重定义fputc函数int fputc(int ch, FILE *f){ if(USART_PRINTF_FLAG==2){while((USART2->SR&0X40)==0){};USART2->DR = (u8) ch; }else{while((USART3->SR&0X40)==0){};USART3->DR = (u8) ch; }return ch;}//注意:与正点原子不同的是补充了一个发送标志(全局变量),判断是用哪个串口进行发送,用于处理多串口收发