单片机
返回首页

【菜鸟入门】stm32 之 USART

2020-03-03 来源:eefocus

这是学习stm32的第四天了,怎么说呢?感触最大的是,细心最重要,为什么呢?昨天,一个二进制到十六进制换算出来问题,导致一个问题纠结了一下午,今天,在初始化时钟的时候,把9写成10,导致,串口到下午才调试好。


好吧,现在开始说串口。


在我的板子上,USART1对应的PIN是


PA10 --- RX INPUT   Mode:0x8

PA9 ---TX OUTPUT  Mode:0xb


其实串口初始化也就分下面几步:


(1)PIN管脚时钟使能,特殊功能寄存器使能,即GPIOA和USART1时钟使能;


(2)USART管脚配置,PA10配置成输入模式:0x8;PA9配置成输出模式;【前面讲过怎么配置】


(3)USART Reset;记得关闭Reset;


(4)USART 波特率设置;


(5)USART寄存器配置;


(6)USART中断配置;


还是老规矩,先附上代码:


/* USART0

PA10 --- RX INPUT  M:0x8

PA9 --- TX OUTPUT M:0xb

*/

#define CPU_RATE_72M 72

 

int rs232_init(u32 cpu_rate,u32 baud)

{

float div;

u16 div_int = 0;

u16 div_float = 0;

/* Get Div Baud */

div = (float)(cpu_rate*1000000)/(16*baud);

div_int = div;

div_float = 16*(div - div_int);

div_int <<= 4;

div_int += div_float;

RCC->APB2ENR |= 1<<2;

RCC->APB2ENR |= 1<<14;

GPIOA->CRH &= ~(0xff<<4); //clear CRH at bit 10:9

GPIOA->CRH |= 0x8b << 4; //set CRH at bit 10:9

RCC->APB2RSTR |= 1<<14; //Reset USART0

RCC->APB2RSTR &= ~(1<<14);//Stop Reset USART0

/* config USART */

USART1->BRR = div_int; // Set Baud Rate

 

USART1->CR1 &= ~(1<<12); // Set Data bit :8bit

USART1->CR1 &= ~(1<<10); // CRC

USART1->CR1 |= 1<<8; // Enable PE Interrupt

USART1->CR1 |= 1<<5; // Enable RX Interrupt

USART1->CR1 |= 3<<2; //Enable RX TX

USART1->CR2 &= ~(3<<12); // Stop Bit :00 => 1SB

USART1->CR1 |= 1<<13; // Enable USART

init_interrupt(2,37,3,3);

return 0;

}


APB2ENR寄存器如下,我们要使能IOPA和USART1的时钟所以,APB2ENR |= (1<<2) | (1<<14)

APB2RSTR是外设复位寄存器:我们最好把USART1重新复位下,来确保系统的稳定性:

但是,在复位完成之后,一定要对该控制位置零,停止复位;


APB2RSTR |= 1<<14;


APB2RSTR&=~(1<<14);


USART波特率的设置是整个配置中比较关键的,stm32厂商已经给了我们一个公式:

USARTDIV计算出来,然后需要换算成USART_BRR寄存器需要的模式:我们呢可以先来研究下BRR寄存器:

他是把整数部分存放在4-15bit,小数部分存放在0~3bit


至于小数和整数部分的换算方法,STM也给提供了一个例子:

波特率计算完了,我们就需要对USART的控制寄存器进行设置,USART有三个控制器CR1,CR2,CR3


其中常用的只有CR1,CR2中只需配置一个参数。


关于这两个寄存器的详细信息请看25.6.4~26.6.7章,不过基本上看我的注释就可以看懂;


USART的中断配置,跟昨天那个按键中断配置一样,他的中断向量号是37


今天我重新把中断配置函数进行了整理,大家可以拿去用:


void init_interrupt(u8 group,u8 inter_id,u8 preempting,u8 subpriority)

{

u32 aircr;

u8  ip;

/* Set Group :2 */

aircr = SCB->AIRCR; //Get AIRCR register

aircr &= 0x0000f8ff; //Clear Password & PriGroup

aircr |= 0x05fa0000; //Set Password

aircr |= ((~group&0x7)<<8); //Set PriGroup Group:2 0000 0010 => 1111 1101 [5 = 0101b]<<8

SCB->AIRCR = aircr; //Set AIRCR

/* 

* Group 2  2:2

* 0~3 : 0~3

* Set Preempting = 0  Subpriority = 0

* 1001 0000b = 0x00;

*/

if(inter_id<32)

NVIC->ISER[0] = 1<< inter_id;

else

NVIC->ISER[1] = 1<<(inter_id-32); //EXIT15_10 vector:37

switch(group)

{

case 0: ip = 0x0f&subpriority;break;

case 1: ip = (0x08&preempting) | (0x07&subpriority);break;

case 2: ip = (0x0C&preempting) | (0x03&subpriority);break;

case 3: ip = (0x0e&preempting) | (0x01&subpriority);break;

case 4: ip = 0x0f&preempting;break;

default: ip = 0x00;break;

}

NVIC->IP[inter_id] = 0xf0&(ip<<4);

}




他的发送和中断接收函数也都很简单,其中发送和接受标志位,在对数据进行写,或者读的时候他会自动清除

int rs232_send_byte(u8 byte)

{

USART1->DR = byte;

while(0 == (USART1->SR&(1<<6)));

return 1;

}

 

void USART1_IRQHandler(void)

{

if(USART1->SR&(1<<5))

{

rs232_send_byte(USART1->DR);

}

}


有了串口,我们以后调试程序就更方便,我们可以直接把寄存器值读出来,然后对初始化的寄存器值进行研究。

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 如何利用ESP8266制作一个简单的四轴飞行器

  • 非常简单的150W功放电路图

  • 基于IC555的可变PWM振荡器电路

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

    相关电子头条文章