最近开始学正点原子stm32开发板,在学习usart串口通信发现一个问题,就是接受数据是如何保存到USART_RX_BUF中的。正点原子的demo是接收到数据后直接传入USART1->DR中发送出来;但显然在main函数中并没有接受的数据存入USART_RX_BUF的过程。
int main(void){
…………
while(1)
{
if(USART_RX_STA&0x8000){
len=USART_RX_STA&0x3FFF;//得到此次接收到的数据长度
printf("\r\n 您发送的消息为:\r\n\r\n");
for(t=0;t<len;t++){
USART1->DR=USART_RX_BUF[t]; //写入DR寄存器直接发送
while((USART1->SR&0X40)==0); //等待发送结束
}
…………
}
}
于是转到usart.c文件中,该文件只有两个函数;一个是中断处理函数;这里很显然包括了接受数据写入USART_RX_BUF的过程;但是该函数在main中并没有被调用。
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
void USART1_IRQHandler(void)
{
u8 res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART1->SR&(1<<5)) //接收到数据
{
res=USART1->DR;
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}else{ //还没收到0X0D
if(res==0x0d)USART_RX_STA|=0x4000;
else{
USART_RX_BUF[USART_RX_STA&0X3FFF]=res;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1)) USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
#endif
于是继续看初始化函数;该函数对寄存器进行了一系列初始化,并且在最后面设置了中断的函数,但是传入的变量是USART1_IRQn而不是USART1_IRQHandler;很显然它们之间是相关联的,但是它们是怎么关联上的呢?
void uart_init(u32 pclk2,u32 bound)
{
……………………
#if EN_USART1_RX //如果使能了接收
//使能接收中断
USART1->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQn,2); //组2,最低优先级
#endif
}
基于上面的问题进行了检索,发现并没有一个详细的解释,有一篇相关的来自于2017年的博文,找到的一点思路,该博文po在此处:STM32是如何进入中断服务函数xxx_IRQHandler的_中断服务函数是如何进入的_小时候挺菜的博客-CSDN博客该文提到了在启动文件startup_stm32f10x_hd.s中,有一段汇编:
DCD USART1_IRQHandler 其中DCD是一条数据定义伪指令,用于分配一片连续的字存储单元并用指定的数据初始化。
但这只能说明在编译过程为USART1_IRQHandler开辟了一片地址,但仍然没有介USART1_IRQn与USART1_IRQHandler的连接过程,于是对USART1_IRQn进行了检索,在stm32f10x.h发现了其定义:
#ifdef STM32F10X_HD
……………………
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
USART3_IRQn = 39, /*!< USART3 global Interrupt */
………………
#endif /* STM32F10X_HD */
然后仔细对比了一下,两者顺序完全相同(见下图对比)。因此猜想USART1_IRQn和USART1_IRQHandler指向同一个地址。