STM32串口通信

我的第一个项目是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键程序不会执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容