STM32串口通信

作者: X_xxieRiemann | 来源:发表于2017-08-06 14:10 被阅读0次

我的第一个项目是STM32嵌入式系统设计,包括了硬件部分和软件部分。项目与公共卫生学院合作,主要内容是关于药剂检测。
之前做过用51单片机开发板读取温度湿度的小项目,主要的任务是代码的编写,相比于51单片机这种入门级别的MCU,STM32在各方面性能都领先51单片机,但是使用起来也复杂不少,光是选择用库函数法或是寄存器法编程就让人纠结。
我主要通过视频+相关文档的方法来学习STM32。
视频地址:【正点原子】STM32开发板实验教程,视频讲的很细,电路原理图也都有讲,不过涉及到原理乏味而又高深。
相对应的实验配套文档:正点原子战舰版资料
其中个人认为最有用的是:
①软件资料下的软件压缩包,有MDK5的安装包和各种实用软件,比如程序下载软件、串口软件
②STM32F1开发指南,包括库函数版和寄存器版。
③STM32参考资料文件夹下的STM32中文参考手册
④STM32F103ZET6
⑤程序源码,包括库函数版和寄存器版。

STM32快速简介

我总结了下我对STM32的理解:

STM32是ST公司生产的MCU,32位,内核是ARM公司的Cortex内核。Cortex内核有A,R,M三个系列,STM32主要是Cortex-M系列。Cortex-M3内核在各方面都领先于ARM7内核,成本也更低。

配置程序的模板框架其实挺复杂的,但其实不需要自己一步一步的建立,直接套用程序源码中的模板就好了。现成的有STM32F103系列和STM32F407系列的模板。

为了方便开发,我最后选择的是库函数法。本文以串口通信作为例子,尽量详尽的给出模板,中间必须要用到的头函数定义和GPIO函数也进行了一定的介绍。

头文件设置
#ifndef __XXX_H
#define __XXX_H                
#include "XXXXXX.h"
void XXX//各种函数声明
#define LED0 PAout(1)//各种宏定义,PAout(1)这样的位带操作在sys.h中定义

#endif
GPIO的设置,包括输入输出
(1)初始化
 GPIO_InitTypeDef  GPIO_InitStructure;  //定义名称为GPIO_InitStructure的结构体
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;               //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //IO口速度为50MHz,数值感觉不太重要
 GPIO_Init(GPIOB, &GPIO_InitStructure);                  //根据设定参数初始化GPIOB.5

其中GPIO_InitTypeDef是一个结构体,主要包括GPIO的引脚、速度、模式三个参数。

typedef struct
{
  uint16_t GPIO_Pin;         //GPIO_Pin_0到GPIO_Pin_15         
  GPIOSpeed_TypeDef GPIO_Speed; 
  GPIOMode_TypeDef GPIO_Mode;  
}GPIO_InitTypeDef;

GPIO_Speed的参数规范为:

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

输出模式必须配置,输入模式无须配置。设置端口的翻转速度级别为50MHz,这种级别时端口能输出频率很高的信号,但要求外设的容性负载很小。另外还有2MHz和10MHz级别的,能驱动容性负载较大的外设。
GPIO_Mode的参数规范为:

typedef enum
{ GPIO_Mode_AIN = 0x0,              //模拟输入
  GPIO_Mode_IN_FLOATING = 0x04,     //浮空输入
  GPIO_Mode_IPD = 0x28,             //下拉输入  
  GPIO_Mode_IPU = 0x48,             //上拉输入
  GPIO_Mode_Out_OD = 0x14,          //开漏输出
  GPIO_Mode_Out_PP = 0x10,          //通用推挽输出
  GPIO_Mode_AF_OD = 0x1C,           //复用开漏输出
  GPIO_Mode_AF_PP = 0x18            //复用推挽输出
}GPIOMode_TypeDef;

各种输出输入模式应用场合:
http://www.openedv.com/posts/list/21980.htm

(2)信号输出和检测输入

有相应的库函数

GPIO_SetBits(GPIOE,GPIO_Pin_5);   //LED1对应引脚GPIOE.5拉高
GPIO_ResetBits(GPIOB,GPIO_Pin_5);  //LED0对应引脚GPIOB.5拉低
GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4);//读取GPIOE.4的输入

用位带操作法比较方便

PAout(1) = 1;
PBin(2);
按键设置(以低电平触发为例)

其中u8是无符号数字8位的意思,进行过宏定义。

//mode=0时,不支持连按;mode=1时,支持连按
u8 KEY_Scan(u8 mode)
{    
    static u8 key_up=1;//按键按松开标志
    if(mode)key_up=1;  //支持连按         
    if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
    {
        delay_ms(10);//去抖动 
        key_up=0;
        if(KEY0==0)return KEY0_PRES;
        else if(KEY1==0)return KEY1_PRES;
        else if(KEY2==0)return KEY2_PRES;
        else if(WK_UP==1)return WKUP_PRES;
    }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;      
    return 0;// 无按键按下
}
串口通信

串口配置的一般步骤(以USART1为例,PA9为TX发送端,PA10为RX接收端为例):
①串口时钟使能,GPIO时钟使能:

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);    

其他串口可能是RCC_APB1PeriphClockCmd();
②串口复位(可不写):

USART_DeInit(USART1);

③GPIO端口模式设置:

STM32中文参考手册P110
GPIO_InitTypeDef  GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;               
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;    
GPIO_Init(GPIOA, &GPIO_InitStructure);               

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;              
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);    

④串口参数初始化:

USART_InitTypeDef  USART_InittStructure;

USART_InittStructure.USART_BaudRate = 115200;  //波特率
USART_InittStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流设置
USART_InittStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //接收发送模式
USART_InittStructure.USART_Parity = USART_Parity_No; //奇偶校验位
USART_InittStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InittStructure.USART_WordLength = USART_WordLength_8b; //字长
     
USART_Init(USART1, &USART_InittStructure);

⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //分组2,放到主函数main的开头位置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //设置中断类型,USART_IT_RXNE表示接收缓冲区非空
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断,在stm32F10x.h中有定义
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //响应优先级为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能

NVIC_Init(&NVIC_InitStructure);

⑥串口使能:

USART_Cmd(USART1, ENABLE);

⑦编写中断处理函数:

//会和system文件夹里的usart.h有冲突,删掉usart.h。
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
              {
   
               }
}

⑧串口数据收发操作:

USART_SendData(USART1, uint16_t Data);
USART_ReceiveData(USART1);

串口通信需要的软硬件设置:
①安装CH340驱动(在软件目录下),让电脑USB口能变成串口
②开发板USB口选择USB_232(如图)
③PA9、PA10通过跳线帽分别与RXD、TXD相连(如图)


利用串口输入指令控制程序
 int main(void)
 {      
    u16 len;
    u8 flag = 0;
    delay_init();            //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);   //串口初始化为115200
    LED_Init();              //LED端口初始化
    KEY_Init();          //初始化与按键连接的硬件接口
    MCP9808_init(); //温度传感器初始化
    while(1)
    {
        if(USART_RX_STA&0x8000) //第15位标志位为1时表示接收完成
        {                      
            len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度,第0位~第13位
            
            if(USART_RX_BUF[len-1]=='E')//指令以E(END)结束
            {
                if(USART_RX_BUF[0]=='R'&USART_RX_BUF[1]=='T'&USART_RX_BUF[2]==' '&len==4)  //指令为RT E
                {
                    printf("温度为%.2f℃\r\n",MCP9808_ReadTP());  //显示温度
                    flag = 0;
                }
                else
                    flag = 1;
            }
            else
                flag = 1;       
            if(flag==1)
            {
                flag =0;
                printf("错误\r\n");
            }
            else
                printf("代码已执行\r\n");
            USART_RX_STA = 0;
        }
    }    
 }

可以根据需求再增加指令。

关于串口1下载程序:
下载软件设置

orient/strip%7CimageView2/2/w/1240)
BOOT0=1,BOOT1=0,如果下载一直识别不出来,尝试按一按RST键。
下载完成后,由于软件勾上了编成后执行,程序会开始执行。
若需要按RST键复位程序,需要再把BOOT0拉低。否则按RST键程序不会执行。

相关文章

  • 单片机数据包的发送

    姓名:赵宗明 学号:19021211230 【嵌牛导读】:STM32 串口通信 数据包 【嵌牛鼻子】:利用单片...

  • 单片机数据包的接收

    姓名:赵宗明 学号:19021211230 【嵌牛导读】:STM32 串口通信 数据包 【嵌牛鼻子】:利用电脑...

  • 基于STM32的串口数据包的传输

    姓名:赵宗明 学号:19021211230 【嵌牛导读】:STM32 串口通信 数据包 【嵌牛鼻子】:利用电脑...

  • STM32和树莓派串口透传

    最近做一个项目需要STM32和树莓派进行串口通信,实现原理如下: 第一步:使用USB转TTL分别调试STM32和树...

  • unix socket实现进程通信

    2017-5-10 需求: arm与stm32在android平台中通信,串口由stm操作,由arm发送指令给st...

  • STM32的串口通信

    在基础实验成功的基础上,对串口的调试方法进行实践。硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行...

  • STM32的串口通信

    本篇文章主要讲解一个在开发过程中经常使用到的一个外设---串口。 串口是绝大多数 MCU 中不可或缺的一个外设,同...

  • 循环缓冲区RingBuffer

    stm32和外设通信的时候,需要对外设发来的串行数据做同步。参考过下面这个链接的方法:串口通信帧的同步方法(识别一...

  • STM32-printf重映射串口

    在STM32开发过程中必然需要串口打印参与调试,而往往STM32调试分配串口不会固定,可能是在串口1,也有可能为串...

  • 2018-09-13

    # STM32之串口DMA接收不定长数据 ## 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,...

网友评论

    本文标题:STM32串口通信

    本文链接:https://www.haomeiwen.com/subject/yzgglxtx.html