一、 USART简介
一般使用MAX232芯片在STM32和DB9接头之间进行电平转换,将STM32的PA10(USART1-TX)连接到DB9(公头)的第三引脚。
串口的发送数据和接收数据都是在USART_DR中实现的,为一个双寄存器,包含了TDR和RDR,当向该寄存器写入数据是,串口就会自动发送数据;当收到数据时,也是存在该寄存器中可以直接读出。
串口的状态通过状态寄存器USART_SR读取,比较重要的几位如下:
二、USART寄存器配置(全双工、异步)
l 串口工作模式配置
1. 使能USART时钟,配置GPIOA9、10;
查找《STM32参考手册》中系统结构图得知USART1和GPIOA均挂载在APB2时钟线上,查找APB2外设时钟使能寄存器(RCC_APB2ENR),使能USART和GPIOA的时钟:
RCC->APB2ENR |= 1<<2; //使能GPIOA时钟
RCC->APB2ENR |= 1<<14; //使能USART1时钟
参考《STM32参考手册》中GPIO章节配置PA9为复用推挽输出,PA10为浮空输入:
GPIOA->CRL &= 0xFFFFF00F; //选中PA9、PA10
GPIOA->CRL |= 0xFFFFF4B0; //PA9复用推挽输出,PA10浮空输入
2. 使能USART模块,配置USART模块的数据模式
USART1->CR1 &=0x200C; //一个起始位,8个数据位,默认一个停止位,无校检位,禁止各种中断
//USART->CR2 |= 0x00<<12; // 1个停止位 ,可不设置默认一个停止位
3. 设置USART通讯波特率
USART1->BRR =(0x1D4<<4)| 0xC; //设置波特率为9600bps
/******************参数设置说明**********************************
查找《STM32参考手册》中“表176 设置波特率时的误差计算”,如表1-1。
若设置串口1通讯波特率为9600bps,串口1挂载在APB2时钟线上,因此,查表可得“置于波特率寄存器中的值”为468.75。
该数据的整数部分为USART->BRR的高12位,改数据的小数部分*16为USART->BRR的低四位。
Dec(468) = 0x 1D4;
Dec(0.75*16) = 0xC;
故:USART->BRR =(0x1D4<<4)| 0xC。
********************************************************************/
4. 复位串口
USART1->APB2RSTR |= 1<<14;
5. 停止复位串口
USART1->APB2RSTR &= ~(1<<14); //初始化串口复位寄存器位
6. 使能接收
USART->CR1 |= 0xc; //接收和发送使能
l 中断配置(后续单独补充说明)
1. 中断优先级分组
SCB->AIRCR &=0x05FAF8FF; //优先级分组为3
SCB->AIRCR |=0x05FA0400;
2. 串口中断总开关使能
查找stm32f10x.h得到USART1的中断号为37:
NVIC->ISER[1] = 1<<5; //使能37 位上的串口中断
3. 串口中断优先级配置
NVIC->IP[37] = 0x30;
USART->CR1 |= 1<<5; //RXNEIE,接收完成中断使能
三、USART库配置
/**************异步不用配置时钟*************
USART_InitTypeDef USART_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, Enable);
//PA9-TX,PA10-RX
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength= USART_WordLength_8b;
USART_InitStruct.USART_StopBits =USART_StopBits_1;
USART_InitStruct.USART_Parity =USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
USART_Init(USART1,USART_InitStruct);
USART_ITConfig(USART1, USART_IT_RXNE, Enable);
USART_ITConfig(USART1, USART_IT_IDLE, Enable);
USART_Cmd(USART1, Enable);
优先级配置:
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_0 );
NVIC_InitStruct.NVIC_IRQChannel =USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =NVIC_PriorityGroup_0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority =1;
NVIC_InitStruct.NVIC_IRQChannelCmd = Enable;
NVIC_Init(NVIC_InitStruct);
四、USART数据接收/发送
寄存器版
发送数据:
void USART1_Send_ASCII_Data(char TxData)
{undefined
USART1->DR = TxData;
Delay; //延时
While((USART->SR&0x00000040)==0); //等待发送完毕,TC(0x00000040)
}
中断接收:
User/stm32f10x_it.c
/************中断服务函数是根据函数名来区分在.s的启动文件中说明*************/
Void USART1_IRQHandler()
{undefined
u8 data;
if(USART1->SR&(1<<5)) //接收器非空
{undefined
Data = USART1->DR;
}
}
库操作版:
void USART1_Send_ASCII_Data(char TxData)
{undefined
USART_SendData(USART1, TxData);
Delay; //延时
While(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); //TC:发送数据完毕;TXE发送数据寄存器为空
}
中断接收:
void USART1_IRQHandler(void)
{undefined
if(USART_GetITStatus(USART1, USART_FLAG_RXNE)=SET)
BUFFER1[i] = USART_ReceiveData(USART1);
i++;
if(USART_GetITStatus(USART1, USART_IT_IDLE)=SET) //一帧完毕
i= 0;
}
五、Printf重定向
配置好串口后可以通过Printf重定向由串口往计算机超级终端或者串口调试软件打印信息。
重定向是指用户可以自重写C的库函数,当连接器检查到用户编写了与C库函数相同名字的函数时,优先采用用户编写的函数,这样用户就可以实现对库的修改了。
重定向Printf()函数,我们需要重写fputc()这个C标准库函数,因为printf()在C标准库中实质是一个红,最终是调用了fputc()这个函数。
库操作版:
int fputc(int ch, FILE *f)
{undefined
USART_SendData(USART1, (unsighed char)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
return(ch);
}
寄存器版:
int fputc(int ch, FILE *f)
{undefined
USART1->DR = (unsigned char)ch;
While((USART->SR&0x00000040)==0);
return(ch);
}