STM32关于串口编程的心得

2019-07-20 05:04发布

本帖最后由 七剑天山 于 2018-11-13 11:16 编辑

初学STM32,每一个环节都是新大陆。所以每一个环节都是新的挑战,我想这其实对每一个新手都有这样的过程。
首先接触到了串口通讯。我也是这几天才接触到这个内容,看了原子的书籍,例子程序,均没有办法进行正常所需要的通讯,可以说达到了让人生不如死的崩溃地步,但是最终还是成功了。所以把我的经验进行分享。

首先用实验3串口通讯例程。

第一步了解串口通讯的结构。
USART1,硬件收发接口为PA9,PA10,
在文件usart.c中就能找到设置端口的代码相应的设置函数uart_init(u32 pclk2,u32 bound);
RCC->AHB1ENR|=1<<0;           
        RCC->APB2ENR|=1<<4;         
        GPIO_Set(GPIOA,PIN9|PIN10,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA9,PA10,
        GPIO_AF_Set(GPIOA,9,7);        //PA9,AF7
        GPIO_AF_Set(GPIOA,10,7);      //PA10,AF7         
其它代码顺序往下看就可以了。
从设置中可以看到用于串口收发的硬件端口为PA9,PA10,所以串口调试线等接到这两个端口上就可以了。可以根据需求设置到其它有通讯接口的端口。

1、首先说串口数据的接收。
当所设定的相应的硬件端口有数据接收进来时会自动触发串口接收中断函数程序。void USART1_IRQHandler(void),
他在 startup_stm32f767xx.s等相应的启动文件中被定义成中断函数。
131               DCD     USART1_IRQHandler                 ; USART1  

所以数据的接收过程是怎么运行的就可以去看此函数的程序。
void USART1_IRQHandler(void)
{
        u8 res;        
#if SYSTEM_SUPPORT_OS                 
        OSIntEnter();   
#endif
        if(USART1->ISR&(1<<5)
        {         
                res=USART1->RDR;
                if((USART_RX_STA&0x8000)==0)
                {
                        if(USART_RX_STA&0x4000)
                        {
                                if(res!=0x0a)USART_RX_STA=0;
                                else USART_RX_STA|=0x8000;
                        }else
                        {        
                                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;
                                }                 
                        }
                }                                                                                                
        }


从程序中可以看到,数据的传输在两个位置;
1、res=USART1->RDR;    //接收的数据传给res
2、USART_RX_BUF[USART_RX_STA&0X3FFF]=res;      //res再传给数组中从低到高依次存储。


再看主程序调用:
int main(void)
{
        u8 t;
        u8 len;        
        u16 times=0;  
        u8 led0sta=1;                        
    delay_init(216);               
        uart_init(108,115200);        
        LED_Init();                                 
        while(1)
        {
                if(USART_RX_STA&0x8000)
                {                                          
                        len=USART_RX_STA&0x3fff;
                         printf();
                        for(t=0;t<len;t++)
                        {
                                USART1->TDR=USART_RX_BUF[t];
                                while((USART1->ISR&0X40)==0);
                        }
                        printf(" ");
                        USART_RX_STA=0;
                }else
                {
                        times++;
                        if(times%5000==0)
                        {
                                printf("");
                                printf();
                        }
                        if(times%200==0)printf("");  
                        if(times%30==0)LED0(led0sta^=1);
                        delay_ms(10);   
                }
        }
}

那么讲到了这里,上面那么多是不是很复杂繁琐?所以我们要学会化繁为简的方法。
1、知道端口的对应设置
2、知道接收数组函数USART_RX_BUF[0~n]
那么在主程序内任意的地方就可以通过此函数进行使用了

如串口接收到3个字符985,那么在程序中就可以这样用

a=USART_RX_BUF[0];       //数组的第零位的数传给a
b=USART_RX_BUF[1];       //数组的第1位的数传给b
c=USART_RX_BUF[3];       //数组的第1位的数传给c
运行后
a=9
b=8
c=5

记得运行完成后把数组清空以便下一次接收数据
USART_RX_BUF[0]=0x0;     //数组第零位就清空了。
USART_RX_BUF[1]=0x0;     //数组第1位就清空了。
USART_RX_BUF[2]=0x0;     //数组第2位就清空了。
接收过程完成后再做最终的扫尾工作
USART_RX_STA=0;            //将接收状态标志清零,以便下次接收数据使用。

下面是一个重要的问题一定要注意,上述函数接收程序所传输的是ascii字符。

字符0~9对应的十进制数是48~57,两者相差数48.如接收到的字符数5,那么对应的十进制数是53,那么就该减去48后变成十进制的5.那么上面的函数接收程序就可以如下编写。
a=(USART_RX_BUF[0]-48)*100+(USART_RX_BUF[1]-48)*10+(USART_RX_BUF[2]-48)    //百位乘100,十位乘10,
这样接收到的字符串"985"就转换成了十进制985了。就可以通过它进行十进制的加减乘除等运算了。

最后讲串口的发送。
只记住一条:
在主程序中的任意的地方插入发送语句:
USART1->TDR=m;      //将m中的数通过串口输出
或者
USART1->TDR=0x15;      //直接将数15通过串口输出
等均可。

//---------------------------------------------
//最终总结:熟悉我上面说的方法后最终如下在主程序内需要的任何位置简单方便使用就可以了,而不需要漫天飘雪的丈二摸不清头脑乱抓一气。
//---------------------------------------------
接收:
a=USART_RX_BUF[0];       //数组的第零位的数传给a  
USART_RX_BUF[0]=0x0;     //数组第零位清空。
USART_RX_STA=0;            //将接收状态标志清零,以便下次接收数据使用。
发送:
USART1->TDR=m;      //将m中的数通过串口输出

整个串口通讯最终浓缩成了这4条语句,是不是非常精简,高效,实用。





友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。