STM32串口学习总结(经典)

本文介绍STM32F103RCT6单片机的串口通讯实践,包括串口中断服务函数的设计与应用、全局变量的声明与使用等关键技术点。通过实例讲解如何在两个单片机之间建立通讯,并分享了串口调试助手的使用技巧。

主函数代码如下:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "arduino.h"
//ALIENTEK Mini STM32¿ª·¢°å·¶Àý´úÂë3
//´®¿ÚʵÑé   
//¼¼ÊõÖ§³Ö£ºwww.openedv.com
//¹ãÖÝÊÐÐÇÒíµç×ӿƼ¼ÓÐÏÞ¹«Ë¾
 int main(void)
 {  
    u8 t;
    u8 len; 
    u16 times=0; 
    u8 ax;
    //u8 bx='*';      //*µÄʵ¼ÊÖµÆäʵ´ú±í0x42Ò²¾ÍÊÇASCIIµÄÖµÊÇ42

    delay_init();            //ÑÓʱº¯Êý³õʼ»¯   
    NVIC_Configuration();// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é
    uart_init(9600);     //´®¿Ú³õʼ»¯Îª9600
    LED_Init();          //³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú 
  USART3_Config(115200);
    while(1)
    {


        delay_ms(100);
        LED0=1;
        LED1=1;
        //GPIO_ResetBits(GPIOA,GPIO_Pin_8);

        ax=arduino_Analysis();
        //printf("sudo=%d \r\n",sudu);
        //printf("ax=%d \r\n",ax);
        //printf("cx=%d \r\n",cx);
        //printf("%d \r\n",bx);
        //delay_ms(1000);






















        //////////////////////////////////Ô­º¯Êý
//      LED0=!LED0;
//      if(USART_RX_STA&0x8000)
//      {                      
//          len=USART_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È
//          printf("\r\nÄú·¢Ë͵ÄÏûϢΪ:\r\n");
//          for(t=0;t<len;t++)
//          {
//              USART1->DR=USART_RX_BUF[t];
//              while((USART1->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø
//          }
//          printf("\r\n\r\n");//²åÈë»»ÐÐ
//          USART_RX_STA=0;
//      }else
//      {
//          times++;
//          if(times%5000==0)
//          {
//              printf("\r\nALIENTEK MiniSTM32¿ª·¢°å ´®¿ÚʵÑé\r\n");
//              printf("ÕýµãÔ­×Ó@ALIENTEK\r\n\r\n\r\n");
//          }
//          if(times%200==0)printf("ÇëÊäÈëÊý¾Ý,ÒԻسµ¼ü½áÊø\r\n");  
//      //ÉÁ˸LED,ÌáʾϵͳÕýÔÚÔËÐÐ.
//          delay_ms(10);   
//      //}
//  }    
}
}

需要串口服务工程
建立与Arduino板子的通讯
.c程序如下:

#include "arduino.h"



u8 Res=0;
int i;
u8 Arduino_sudo;
u8 Arduino_jiaodu;
u8 sudu;
u8 jiaodu;
u8 x=7;
char cx;
u8 USART3_RX_BUF[USART_REC_LEN];     //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.
//½ÓÊÕ״̬
u8 Arduino_Receive_Data[10];
u8 Arduino_receive_counter=0;
u8 Arduino_receive_flag=0;
//u8 Arduino_receive_temp[10]={0x42,0x39,0x49,0x39,0x45,0x39,0x49,0x54,0x39,0X39};
u8 Arduino_receive_temp[10];
//u8 res[8];
//bit15£¬   ½ÓÊÕÍê³É±êÖ¾
//bit14£¬   ½ÓÊÕµ½0x0d
//bit13~0£¬    ½ÓÊÕµ½µÄÓÐЧ×Ö½ÚÊýÄ¿
u16 USART3_RX_STA=0;       //½ÓÊÕ״̬±ê¼Ç   







void USART3_Config(u32 bound)       //Á¬½ÓÊý´«µç̨  ³õʼ»¯ ÅäÖÃUSART2
{
    GPIO_InitTypeDef     GPIO_InitStructure;   //´®¿Ú¶Ë¿ÚÅäÖýṹÌå±äÁ¿
    USART_InitTypeDef    USART_InitStructure;  //´®¿Ú²ÎÊýÅäÖýṹÌå±äÁ¿
    NVIC_InitTypeDef   NVIC_InitStructure;

    //µÚ1²½£º´ò¿ªGPIOºÍUSART²¿¼þµÄʱÖÓ
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    //´ò¿ªGPIOAʱÖÓºÍGPIOA¸´ÓÃʱÖÓ
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);  //´ò¿ª´®¿Ú¸´ÓÃʱÖÓ
    USART_DeInit(USART3);  //¸´Î»´®¿Ú1

    //µÚ2²½£º½«USART2 Tx£¨·¢Ëͽţ©µÄGPIOÅäÖÃÎªÍÆÍ츴ÓÃģʽ
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //´®¿Ú2·¢ËͽÅ
    //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;          //¸´ÓÃÍÆÍìÊä³ö
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      //Êä³öËÙ¶È50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);                 //³õʼ»¯GPIOA

    //µÚ3²½£º½«USART2 Rx£¨½ÓÊսţ©µÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;             //´®¿Ú2½ÓÊÕ½Å
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //¸¡¿ÕÊäÈë
    //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //ÉÏÀ­ÊäÈë
    GPIO_Init(GPIOB, &GPIO_InitStructure);                 //³õʼ»¯GPIOA



    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //ÇÀÕ¼ÓÅÏȼ¶ 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶ 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ ͨµÀʹÄÜ
    NVIC_Init(&NVIC_InitStructure);  //ÖжÏÓÅÏȼ¶³õʼ»¯



    //µÚ4²½£ºÅäÖÃUSART1²ÎÊý
    USART_InitStructure.USART_BaudRate             = bound;                          //²¨ÌØÂÊÉèÖãº57600
    USART_InitStructure.USART_WordLength           = USART_WordLength_8b;            //Êý¾ÝλÊýÉèÖãº8λ
    USART_InitStructure.USART_StopBits             = USART_StopBits_1;               //ֹͣλÉèÖãº1λ
    USART_InitStructure.USART_Parity               = USART_Parity_No;                //ÊÇ·ñÆæÅ¼Ð£Ñ飺ÎÞ
    USART_InitStructure.USART_HardwareFlowControl  = USART_HardwareFlowControl_None; //Ó²¼þÁ÷¿ØÖÆÄ£Ê½ÉèÖãºÃ»ÓÐʹÄÜ
    USART_InitStructure.USART_Mode                 = USART_Mode_Rx ;//| USART_Mode_Tx;   //½ÓÊÕÓë·¢ËͶ¼Ê¹ÄÜ
    USART_Init(USART3, &USART_InitStructure);                                        //³õʼ»¯USART2





    //´ò¿ª·¢ËÍÖжϺͽÓÊÕÖжÏ(Èç¹ûÐèÒªÖжÏ)
     // USART_ITConfig(USART2, USART_IT_TXE, ENABLE);  // ʹÄÜÖ¸¶¨µÄUSART1·¢ËÍÖÐ¶Ï £»
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // ʹÄÜÖ¸¶¨µÄUSART1½ÓÊÕÖÐ¶Ï £»

    //µÚ5²½£ºÊ¹ÄÜ USART2£¬ ÅäÖÃÍê±Ï
    USART_Cmd(USART3, ENABLE);                             //ʹÄÜ USART2

    //ÈçÏÂÓï¾ä½â¾öµÚ1¸ö×Ö½ÚÎÞ·¨ÕýÈ··¢ËͳöÈ¥µÄÎÊÌâ
   USART_ClearFlag(USART3, USART_FLAG_TC);                //Çå´®¿Ú2·¢ËͱêÖ¾

}



void USART3_IRQHandler(void)                    //´®¿Ú3ÖжϷþÎñ³ÌÐò
    {



    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //½ÓÊÕÖжÏÓÐЧ,Èô½ÓÊÕÊý¾Ý¼Ä´æÆ÷Âú
     {

            Arduino_receive_temp[Arduino_receive_counter]=USART_ReceiveData(USART3);


            // Res=USART_ReceiveData(USART3);
            // printf("res=%d",Res);
            // USART_SendData(USART3,Res);
            // LED1=!LED1;
              if((Arduino_receive_counter==0)&&(Arduino_receive_temp[0]!=42)) return;/////87=W Ê×Ö¡
              LED0=0;
//           if( Arduino_Receive_Data[0]!=0x42)
//           {
//                Arduino_receive_counter++;
//           }else

             Arduino_receive_counter++;

               if(Arduino_receive_counter==9)
                 {
                     Arduino_receive_counter=0;
                     Arduino_receive_flag=1;


         }
            }
   }



u8 arduino_Analysis()
{
    if(Arduino_receive_flag==1)
    {

      Arduino_receive_flag=0;

        memcpy(Arduino_Receive_Data,Arduino_receive_temp,8);
        //memcpy(Arduino_receive_temp,Arduino_Receive_Data,8);

        LED1=0;
//  for(i=0;i<8;i++)
//      {
//          
//          printf("Arduino_Receive_Data[%d]=%d\r\n",i,Arduino_Receive_Data[i]);
//      }   
}

    printf("sudu=%d \r\n",Arduino_Receive_Data[2]-48);
   jiaodu=(Arduino_Receive_Data[6]-48)*10+(Arduino_Receive_Data[7]-48);
   if(Arduino_Receive_Data[4]==45)
     {
         printf("jiaodu=-%d \r\n",jiaodu);
     }else
     {
         printf("jiaodu=%d \r\n",jiaodu);
     }



    //cx=Arduino_receive_temp[2];


    //Res =Arduino_Receive_Data[Arduino_receive_counter];   //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý
    //return Arduino_receive_temp[2];


    //sudu=Arduino_receive_temp[7];

}





///////////////////////////////////////////////////////////////
Arduino.h的程序如下:
#ifndef _ARDUINO_H
#define _ARDUINO_H
#include "stdio.h"  
#include "usart.h"
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "string.h"
#include "led.h"
#include "sys.h"
#include "delay.h"

void USART3_Config(u32 bound);   //
//void USART3_IRQHandler(void);  
//void TIM4_Init(u16 arr,u16 psc);
//void TIM4_IRQHandler(void);
void TIM4_Init(u16 arr,u16 psc);
u8 arduino_Analysis(void);

#define USART3_REC_LEN              200     //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý 200
#define EN_USART3_RX            1       //ʹÄÜ£¨1£©/½ûÖ¹£¨0£©´®¿Ú1½ÓÊÕ
extern u8 sudu;     
extern char cx;
//Èç¹ûÏë´®¿ÚÖжϽÓÊÕ£¬Ç벻ҪעÊÍÒÔϺ궨Òå







#endif



总结以及函数的说明,今天系统的学习了单片机的串口通讯,简单的建立基于两个单片机的通讯使用单片机型号是stm32f103 rct6
1.在MDK中建立工程的过程中,在函数dianC中定义的相关函数,都在点h中进行相应的声明,但是除了void USART3_IRQHandler(void)以及void TIM4_Init(u16 arr,u16 psc)void TIM4_IRQHandler(void) void TIM4_Init(u16 arr,u16 psc)。像串口中断服务函数这样的函数,在进行编程的时候它是在库函数中已经定义好的函数,只要串口发生中中断,就会进入串口中断函数,执行相应的操作。除此之外所有的自己定义的函数都要在.h中进行相应的声明。
2.要想在.h中进行引用自己编写工程中的全局变量,例如使用Arduino.c中的变量sudo,要在Aduino.h中像如下:extern u8 sudu;外部一下才能够使用
3.如果想在main.c中使用某个.c文件中相应的函数处理的某个数据,当遇到需要一个以上的数据的时候,使用return语句就显得不合时宜,return处理这样的数据也有点吃力,这时候可以考虑使用全局变量并在Arduino.h中进行extern一下就行了,使用的实例如下所示:

u8 Res=0;
int i;
u8 Arduino_sudo;
u8 Arduino_jiaodu;
u8 sudu;
u8 jiaodu;
u8 x=7;
char cx;
u8 arduino_Analysis()
{
    if(Arduino_receive_flag==1)
    {

      Arduino_receive_flag=0;

        memcpy(Arduino_Receive_Data,Arduino_receive_temp,8);
        //memcpy(Arduino_receive_temp,Arduino_Receive_Data,8);

        LED1=0;
    printf("sudu=%d \r\n",Arduino_Receive_Data[2]-48);
   jiaodu=(Arduino_Receive_Data[6]-48)*10+(Arduino_Receive_Data[7]-48);
   if(Arduino_Receive_Data[4]==45)
     {
         printf("jiaodu=-%d \r\n",jiaodu);
     }else
     {
         printf("jiaodu=%d \r\n",jiaodu);
     }

    sudu=Arduino_receive_temp[7];

}
}

sudu=Arduino_receive_temp[7];这时候在主函数想要引用只需要在Arduino.h中extern一下sudu就行了。全局变量可以直接相当于函数的返回在主函数中使用

4.串口中断函数void USART3_IRQHandler(void)只要串口3进入中断,就会跳到串口中断函数void USART3_IRQHandler(void)处理串口中断函数中的相应的命令。

5.关于串口调试助手相关的说明,在进行这个实验的时候,由于串口3使用的bound是115200,但是串口1使用的bound是9600。当你使用串口打印函数:printf的时候,其实库函数中是默认使用串口1进行打印的,因此配置串口的使用9600,而不是115200.因为虽然你使用的是串口3进行通讯,但是单片机与电脑的串口助手进行通讯使用的是串口1,因此无论在任何地方使用串口的打印函数都要使用串口1的配置环境。

6.ASCII问题说明:在进形多机通讯的时候,以Arduino板子为例。当Arduino板子发来数字1的时候,32的板子接收过来就是一个数字1,但是当Arduino的板子发来的是一串字符串的时候比如:‘,6,-,11,’,这个时候其实32的板子接收的是一串数字(补充:串口中所定义的8bit(11111111)0-255,字节(byte)这是计算机中数据类型最基本的单位了,8bit 组成1byte,因此串口在进行数据的传输的过程中是每次传输八个比特,一个字节也就是数据被拆分成一个一个字符的 进行数据传送因此,数据,6,-,11,被拆分为(42 44 54 44 45 44 49 49)ASCII的形式)
如下形式

if((Arduino_receive_counter==0)&&(Arduino_receive_temp[0]!=42)) return;

if((Arduino_receive_counter==0)&&(Arduino_receive_temp[0]!=0x2a)) return;

所实现的功能是一样的,进行通讯的时候,其它的单片机传过来的数据都是一个一个的数字(0-255)形式进行解析的,因此开头的“”*“”的ASCII码就是42=0x2a写成十六进制的还是十进制的都行,进行编译之后单片机所接受的二进制的数是一样的。

6.函数怎样处理的说明,尽量不要在中断服务函数中进行数据的处理,加上一个标志位再在中断函数的外部进行函数的处理如下:

void USART3_IRQHandler(void)                    //´®¿Ú3ÖжϷþÎñ³ÌÐò
    {



    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //½ÓÊÕÖжÏÓÐЧ,Èô½ÓÊÕÊý¾Ý¼Ä´æÆ÷Âú
     {

            Arduino_receive_temp[Arduino_receive_counter]=USART_ReceiveData(USART3);


            // Res=USART_ReceiveData(USART3);
            // printf("res=%d",Res);
            // USART_SendData(USART3,Res);
            // LED1=!LED1;
              if((Arduino_receive_counter==0)&&(Arduino_receive_temp[0]!=42)) return;/////87=W Ê×Ö¡
              //if((Arduino_receive_counter==0)&&(Arduino_receive_temp[0]!=0x2a)) return;  //˵Ã÷£¬0x2a=42
             LED0=0;
//           if( Arduino_Receive_Data[0]!=0x42)
//           {
//                Arduino_receive_counter++;
//           }else

             Arduino_receive_counter++;

               if(Arduino_receive_counter==9)
                 {
                     Arduino_receive_counter=0;
                     Arduino_receive_flag=1;


         }
            }
   }



u8 arduino_Analysis()
{
    if(Arduino_receive_flag==1)
    {

      Arduino_receive_flag=0;

        memcpy(Arduino_Receive_Data,Arduino_receive_temp,8);
        //memcpy(Arduino_receive_temp,Arduino_Receive_Data,8);

        LED1=0;
    printf("sudu=%d \r\n",Arduino_Receive_Data[2]-48);
   jiaodu=(Arduino_Receive_Data[6]-48)*10+(Arduino_Receive_Data[7]-48);
   if(Arduino_Receive_Data[4]==45)
     {
         printf("jiaodu=-%d \r\n",jiaodu);
     }else
     {
         printf("jiaodu=%d \r\n",jiaodu);
     }

    sudu=Arduino_receive_temp[7];

}
}

就像上面的函数一样定义一个全局的变量u8 Arduino_receive_flag=0;,当进入到中断函数的时候就会是标志位置1,当标志位置1的时候函数u8 arduino_Analysis()中的if语句就开始执行`if(Arduino_receive_flag==1)
{

  Arduino_receive_flag=0;

    memcpy(Arduino_Receive_Data,Arduino_receive_temp,8);
    //memcpy(Arduino_receive_temp,Arduino_Receive_Data,8);

    LED1=0;
printf("sudu=%d \r\n",Arduino_Receive_Data[2]-48);

jiaodu=(Arduino_Receive_Data[6]-48)*10+(Arduino_Receive_Data[7]-48);
if(Arduino_Receive_Data[4]==45)
{
printf(“jiaodu=-%d \r\n”,jiaodu);
}else
{
printf(“jiaodu=%d \r\n”,jiaodu);
}

sudu=Arduino_receive_temp[7];

}`
到此处一个STM32的中断函数学习基本的就可以自己进一步做了

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

andrewbytecoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值