zoukankan      html  css  js  c++  java
  • 浅析STM32 中常用的三个函数(sys.c,delay.c,usart.c)之三

     
    #include "sys.h"
    #include "usart.h"
    //////////////////////////////////////////////////////////////////
    //加入以下代码,支持printf函数,而不需要选择use MicroLIB      
    #if 1
    #pragma import(__use_no_semihosting)             
    //标准库需要的支持函数                 
    struct __FILE 
    { 
        int handle; 
    
    }; 
    
    FILE __stdout;       
    //定义_sys_exit()以避免使用半主机模式    
    void _sys_exit(int x) 
    { 
        x = x; 
    } 
    //重定义fputc函数 
    int fputc(int ch, FILE *f)
    {      
        while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
        USART1->DR = (u8) ch;      
        return ch;
    }
    #endif 
    
    
    //串口1中断服务程序
    //注意,读取USARTx->SR能避免莫名其妙的错误       
    u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
    //接收状态
    //bit15,    接收完成标志
    //bit14,    接收到0x0d
    //bit13~0,    接收到的有效字节数目
    u16 USART_RX_STA=0;       //接收状态标记      
      
    void uart_init(u32 bound){
      //GPIO端口设置
      GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟
      
        //USART1_TX   GPIOA.9
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
      GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
       
      //USART1_RX      GPIOA.10初始化
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
    
      //Usart1 NVIC 配置
      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
      
       //USART 初始化设置
    
        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_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(USART1, &USART_InitStructure); //初始化串口1
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
      USART_Cmd(USART1, ENABLE);                    //使能串口1 
    
    }
    
    void USART1_IRQHandler(void)                    //串口1中断服务程序
        {
        u8 Res;
    
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
            {
            Res =USART_ReceiveData(USART1);    //读取接收到的数据
            
            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;//接收数据错误,重新开始接收      
                        }         
                    }
                }            
         } 
    
    } 

    usart文件夹内包含了 usart.c 和 usart.h 两个文件。这两个文件用于串口的初始化和中断接收。这里只是针对串口 1 ,

    比如你要用串 口 2 或者其他的串口,只要对代码稍作修改就可以了。usart.c 里面包含了 2 个函数一个是 void USART1_IRQHandler(void)

    另外一个是 void uart_init(u32 bound) 里面还有一段对串口 printf 的支持代码,如果去掉,则会导致 printf 无法使用,虽然软件编译不会报错,

    但是硬件上 STM32 是无法启动的,这段代码不要去修改。

     下面将贴上main函数,对这个usart串口中断法如何实现数据的接收和发送的,过程基本如下所述:

    main 函数就是开发板将从电脑虚拟串口助手发送过来的数据接收之后,开发板发送这些接收的数据给电脑的电脑虚拟串口助手。

    #include "led.h"
    #include "delay.h"
    #include "key.h"
    #include "sys.h"
    #include "usart.h"
    
     int main(void)
     {        
         u16 t;  
        u16 len;    
        u16 times=0;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        uart_init(9600);     //串口初始化为115200
         LED_Init();                 //LED端口初始化
        delay_init();             //延时函数初始化      
        KEY_Init();          //初始化与按键连接的硬件接口
         while(1)
        {
            if(USART_RX_STA&0x8000)
            {                       
                len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
                printf("
    您发送的消息为:
    
    ");
                for(t=0;t<len;t++)
                {
                    USART_SendData(USART2, USART_RX_BUF[t]);//向串口1发送数据
                    while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);//等待发送结束
                }
                printf("
    
    ");//插入换行
                USART_RX_STA=0;
            }
            else
            {
    
                times++;
                if(times%5000==0)
                {
                    printf("
    精英STM32开发板 串口实验
    ");
                    printf("正点原子@ALIENTEK
    
    ");
                }
                if(times%200==0)printf("请输入数据,以回车键结束
    ");  
                if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
                delay_ms(10);   
            }
        }     
     }

    下面将是关键的printf支持的原理以及串口中断的处理原理的详解!!!

     

    5.3.1 printf函数支持

    这段引入 printf 函数支持的代码在 usart.h 头文件的最上方,这段代码加入之后便可以通过
    printf 函数向 串口发送我们需要的内容,方便开发过程中查看代码执行情况以及一些变量值。这
    段代码不需要修改,引入到 usart.h 即可。

    //加入以下代码,支持printf函数,而不需要选择use MicroLIB      
    #if 1
    #pragma import(__use_no_semihosting)             
    //标准库需要的支持函数                 
    struct __FILE 
    { 
        int handle; 
    
    }; 
    
    FILE __stdout;       
    //定义_sys_exit()以避免使用半主机模式    
    void _sys_exit(int x) 
    { 
        x = x; 
    } 
    //重定义fputc函数 
    int fputc(int ch, FILE *f)
    {      
        while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
        USART1->DR = (u8) ch;      
        return ch;
    }
    #endif 

    初始化完相关IO口、NVIC中断、串口等之外,还要开启串口接收中断以及串口使能

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
      USART_Cmd(USART1, ENABLE);                    //使能串口1 

    不然,初始化完成之后,串口依然不能正常功能,例如串口通讯,或者通过printf发送数据到串口调试助手。

    这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组USART_RX_BUF一个接收状态寄存器 USART_RX_STA

    (此寄存器其实就是一个全局变量,由作者自行添加。由于它起到类似寄存器的功能,这里暂且称之为寄存器)

    实现对串口数据的接收管理。USART_RX_BUF 的大小由 USART_REC_LEN 定义,也就是 一次接收的数据最大不能超过

    USART_REC_LEN 个字节。 SART_RX_STA 是一个接收状态寄存器其各的定义如下图所示。

    原理:

    当接收到从电脑发过来的数据,把接收到的数据保存在USART_RX_BUF 中,同时在接收状态寄存器( USART_RX_STA )

    中计数接收到的有效数据 个数,当收到回车(回车的表示由 2个字节组成: 0X0D 和 0X0A )的第一个字节 0X0D 时,

    计数器将不再增加,等待 0X0A 的到来,而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。

    如果顺利接收到 0X0A则标记 USART_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,

    从而开始下一次的接收,而如果迟迟没有收到 0X0D ,那么在接收数据超过 USART_REC_LEN 的时候,

    则会丢弃前面的数据,重新接收。中断相应函数代码如下:

    void USART1_IRQHandler(void)                    //串口1中断服务程序
        {
        u8 Res;
    
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
            {
            Res =USART_ReceiveData(USART1);    //读取接收到的数据
            
            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;//接收数据错误,重新开始接收      
                        }         
                    }
                }            
         } 
    
    } 

     请各位大侠,觉得笔者写的不错的,给个赞!

  • 相关阅读:
    yii2中登录后跳转回登录前请求的页面
    第七章 : Git 介绍 (上)[Learn Android Studio 汉化教程]
    第六章:Reminders实验:第二部分[Learn Android Studio 汉化教程]
    第五章:Reminders实验:第一部分[Learn Android Studio 汉化教程]
    第四章:重构代码[学习Android Studio汉化教程]
    第三章:使用 Android Studio 编程[Learn Android Studio 汉化教程]
    第二章:Android Studio概述(一)[学习Android Studio汉化教程]
    第二章:Android Studio概述(二)[学习Android Studio汉化教程]
    第一章 : Android Studio 介绍 [Learn Android Studio 汉化教程]
    一,我的Android Studio 3.0.1 安装过程
  • 原文地址:https://www.cnblogs.com/18689400042qaz/p/13378636.html
Copyright © 2011-2022 走看看