简介:简单实现USART的单字节收发
1.相关寄存器了解
2.代码部分
一、寄存器介绍
(1).USART_SR(状态寄存器)
这里我们只用到TXE、RXNE、其它自行了解。
在发送数据时,需要判断数据寄存器中是否有数据,以便把下一个要发送的数据放到数据寄存器里准备发送。
在开启接收中断时,RXNE会在收到数据后被置位,如何进入到中断函数以便及时接收数据。
[位7]: TXE:发送数据寄存器空 | 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1 寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。 0:数据还没有被转移到移位寄存器; 1:数据已经被转移到移位寄存器。 |
[位5]: RXNE:读数据寄存器非空 | 当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果 USART_CR1寄存器中的RXNEIE为1,则产生中断。对USART_DR的读操作可以将该位清 零。 0:数据没有收到; 1:收到数据,可以读出。 |
(2). USART_DR(数据寄存器)
位8:0 DR[8:0]:数据值 | 包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收 用(RDR),该寄存器兼具读和写的功能。TDR寄存器提供了内部总线和输出移位寄存器之间的 并行接口。RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。 当使能校验位时, 如果是8位的数据长度,则位7就被作为校验位,而数据存放在位6到位0[6:0],一共7个位; 如果是9位的数据长度,则位8就被作为校验位,而数据存放在位7到位0[7:0],一共8个位,刚好一个字节。 |
(3).波特比率寄存器(USART_BRR)
用于配置波特率,并且在通信时不能改变
计算方式:
如何根据要配置的波特率计算出DIV,可参考以下举例:
在STM32F103C8TM6最小系统板中,PCLK2大多配置为72M(72 000 000),现在要配置9600的波特率
那么代入公式:DIV=72M/16/9600=468.75,
然后转换成二进制,DIV=1 1101 0100.11=0X0000 1D4C
(4).控制寄存器 1(USART_CR1)
主要用到UE、M、RXNEIE、TE、RE,初始化时需要把UE、RXNEIE、TE、RE都置“1”,
M置“0”(数据长度为8),其它配置为0就行了。
(5).控制寄存器 2(USART_CR2)
这个寄存器里主要用到了STOP[1:0],一般一个停止位,配置为00,其它用不到也配置为0,
(6).控制寄存器 3(USART_CR3)
这个寄存器跟硬件控制流、DMA等使能有关,用不到,配置为0就行了
要驱动串口,还需配置GPIO、NVIC、SCB,暂时不介绍了。
二、代码
/*******************USART1单字节收发(STM32F103C8T6)********************************/
uint8_t rx_buff;
void usart1_init(void)
{
uint32_t temp;
//检测USART1的工作时钟是否开启,没开启则开启其时钟
if((RCC->APB2ENR&0X00004000)==0)
{
RCC->APB2ENR|=0X00004000;
}
//检测GPIOA的工作时钟是否开启,没开启则开启其时钟
if((RCC->APB2ENR&0X00000004)==0)
{
RCC->APB2ENR|=0X00000004;
}
GPIOA->CRH|=0X000004B0;//PA9(TX复用推挽输出),PA10(RX浮空输入)
USART1->BRR=0X00000271;//115200
USART1->CR1=0X0000102C;//8位字长无校验,TX和RX使能,开启接收中断
USART1->CR2=0X00000000;//一个停止位
USART1->CR3=0X00000000;//关闭其它模式
//中断优先级分组
temp=SCB->AIRCR;
temp&=0X0000F8FF; //清空先前分组
temp|=0X05FA0000; //写入钥匙
temp|=0X00000300;//4位抢占,0位响应
SCB->AIRCR=temp;//配置分组
NVIC->IP[37]=0X05;//优先级5,(0~15)
NVIC->ISER[1]=0X00000020;//使能USART1中断
USART1->CR1|=0X2000;//使能USART1
}
void send_data(uint8_t data)
{
while((USART1->SR&0X00000080)==((uint32_t)0));//等待DR为空
USART1->DR=(data & (uint16_t)0x01FF);
}
uint16_t receive_data(void)
{
return (uint16_t)(USART1->DR & (uint16_t)0x01FF);
}
//USART1中断函数
void USART1_IRQHandler(void)
{
if((USART1->SR&0X00000020)!=((uint32_t)0))//判断是否为接收中断
{
//下面两个函数测试单字节收发功能
rx_buff=receive_data();
send_data(rx_buff);
}
}