STM32 串口通信实验

最新更新时间:2021-12-02来源: eefocus关键字:STM32  串口通信  USART 手机看文章 扫描二维码
随时随地手机看文章

一,串口操作相关库函数:

获取状态标志位函数-操作USART_SR寄存器


// 获取状态标志位

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

// 清除状态标志位

void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

// 获取中断状态标志位

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

// 清除中断状态标志位

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);


接收发送数据函数-操作USART_DR寄存器


// 发送数据到串口(通过写USART_DR寄存器发送数据)

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

// 接收数据(从USART_DR寄存器读取接收到的数据)

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);


串口配置函数


// 串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

// 使能串口

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

// 使能相关中断

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);


二,串口配置的步骤

1,串口时钟使能,GPIO时钟使能

     RCC_APB2PeriphClockCmd()

2,串口复位

     USART_DeInit();

3,GPIO端口模式设置

     GPIO_Init();

4,串口参数初始化

     USART_Init()

5,开启中断并初始化NVIC

     NVIC_Init();

     USART_ITConfig();

6,使能串口

     USART_Cmd();

7,中断函数逻辑

     USARTx_IRQHandler();

8,串口数据发送

     void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

     uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

9,串口传输状态获取

     ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

     void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);


三,串口引脚配置

串口引脚配置

 USART1_TX : 复用推挽输出

 USART1_RX : 浮空输入


四,设计串口通信协议

 数据以(0x0D),(0x0A)结尾(回车,换行符)时,认为数据接收完成

 如:ABCDEFGHIJK…..(0x0D),(0x0A)


五,代码实现

SYSTEM/usart/usart.h头文件


#ifndef __USART_H

#define __USART_H

#include "stdio.h"

#include "sys.h"


#define USART_REC_LEN          200       // 最大接收字节数 200

#define EN_USART1_RX           1


extern u8  USART_RX_BUF[USART_REC_LEN];  // 串口接收数据缓冲数组-200字节


// 16位接收状态标记:

//      0-13位接收有效数据数量  

//      14位:接收到0x0D标志 

//      15位:接收完成标志

extern u16 USART_RX_STA;


//设置串口波特率

void uart_init(u32 bound);


#endif


SYSTEM/usart/usart.c


u8 USART_RX_BUF[USART_REC_LEN];     // 串口接收数据缓冲数组   200字节

// 16位接收状态标记:

//      0-13位接收有效数据数量 

//      14位:接收到0x0D标志 

//      15位:接收完成标志

u16 USART_RX_STA=0;


void uart_init(u32 bound){


  GPIO_InitTypeDef GPIO_InitStructure;

  USART_InitTypeDef USART_InitStructure;

  NVIC_InitTypeDef NVIC_InitStructure;


  // 初始化GPIOA,USART1时钟

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);


  //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);


  //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);


  //Usart1 NVIC 中断优先级配置

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         // 串口1

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;  // 抢占3

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        // 响应1

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 使能-开启

  NVIC_Init(&NVIC_InitStructure);


  //USART配置

  USART_InitStructure.USART_BaudRate = bound;                 // 设置波特率-外部传参

  USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长 8|9

  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(USART1, &USART_InitStructure);       // 初始化串口1

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // 开启串口接收中断

  USART_Cmd(USART1, ENABLE);                      // 使能串口1


}


void USART1_IRQHandler(void)

{

    u8 Res;

    //判断是否是接收中断

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){

        // 读取接收到的数据

        Res =USART_ReceiveData(USART1);    

        // 读取USART_RX_STA-bit15判断是否上一次已经接收完成了,还没有清标志位(外部主函数还没读走)

        if((USART_RX_STA&0x8000)==0){

            // 读取USART_RX_STA-bit14

            if(USART_RX_STA&0x4000){ // 已接收到0x0D

                //本次不是0x0A-错误数据,置位USART_RX_STA重新读取

                if(Res!=0x0a)USART_RX_STA=0;

                else USART_RX_STA|=0x8000;    //本次是0x0A,置位USART_RX_STA-Bit15=1

            } else { // 如果上一次没有接收到0x0D

                //本次是0x0D,置位USART_RX_STA-Bit14=1

                if(Res==0x0d){

                    USART_RX_STA|=0x4000;

                }else{//本次不是0x0D,存入字节数组,更新数量


                    USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;

                    USART_RX_STA++;


                    //判断超长-如果超长,置位USART_RX_STA重新接收

                    if(USART_RX_STA>(USART_REC_LEN-1))

                    {

                        USART_RX_STA=0;

                    }

                }

            }

         }

     }

}


USER/main.c 主函数


#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;                // 每10ms+1


    delay_init();               // 延迟函数初始化

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组2,2位抢占2位响应

    uart_init(115200);          // 设置串口1波特率为115200

    LED_Init();                 // LED端口初始化

    KEY_Init();                 // 按键端口初始化


    // 主循环读取串口数据

    while(1)

    {

        if(USART_RX_STA&0x8000)         // 接收数据完成

        {

            len=USART_RX_STA&0x3fff;    // 读取数据长短

            printf("rn您发送的消息为:rnrn");


            for(t=0;t            {

                USART_SendData(USART1, USART_RX_BUF[t]);              // 向串口1发送数据

                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);// 等待发送完成

            }

            printf("rnrn");         // 换行

            USART_RX_STA=0;             // 置位USART_RX_STA,串口下一次接收使用

        }else // 接收数据未完成或无数据时

        {

            times++;

            if(times%5000==0)                      // 每50秒

            {

                printf("rn串口实验rn");

            }

            if(times%200==0)printf("2m无数据n");   // 每2秒

            if(times%30==0)LED0=!LED0;             // 每300msLED亮灭切换

            delay_ms(10);   // 延时10ms

        }

    }

 }


以上代码实现:

    电脑通过串口助手发送数据给单片机

    单片机接收数据进入接收数据串口中断

    根据通信协议处理数据,保存数据到字节数组

    将接收到的数据回写给串口,并打印输出

关键字:STM32  串口通信  USART 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic556241.html

上一篇:系统初始化函数SystemInit讲解
下一篇:STM32 外部中断EXTI

推荐阅读

STM32单片机-汇编指令1
--------------------------------------------说明:STM32单片机汇编指令使用一STM32单片机汇编指令使用二ARM单片机汇编指令的查找见“STM32单片机二之十五、查找汇编指令”。--------------------------------------------.macro restore_user_regs //宏   ldr r1,[sp, #S_PSR]   ldr lr,[sp, #S_PC]!   @ !用来控制基址变址寻址的最终新地址是否进行回写操作,         
发表于 2022-01-12
<font color='red'>STM32</font>单片机-汇编指令1
STM32-GPRS模块连接系统主站
一、GPRS基础讲解(GSM/CDMA/GPRS介绍)1、通信专业术语BSS--基站子系统,通过无线接口与移动台直接联系,负责在一定区域内和移动台通信。(GSM)BTS--基站收发台,可以看作一复杂的无线调制器,BSS的主要部分,每个分配有若干信道。(GSM)RBS--Radio Base Station,无线基站:RBS是基站内所有设备的总称,在GSM规范中对应的主要部分是BTS,它由BSC来控制,用来提供移动台与系统的无线接口,它是CME20系统中的无线设备部分,主要由无线收发信机构成。BSC--基站控制器,其功能是作为无线电设备与MSC的控制和通信的接口,直接控制BTS。(GSM) GPRS--General Pac
发表于 2022-01-12
STM32-GPRS模块连接系统主站
AD转换汇总(STM32、取平均、过采样)
}-----------------------------------------------------------------------------------------------------三、STM32关于使用定时器触发ADC转换以STM32 ADC的常规通道为例(注入通道类似):配合上ADC外设的框图:如上图,STM32 ADC的常规通道可以由以上6个信号触发任何一个,我们以使用TIM2_CH2触发ADC1,独立模式,每次仅测一条通道,则ADC的配置如下:(以下代码使用STM32固件库V3.5)void ADC_Configuration(void){    ADC_InitTypeDef ADC_InitStructure;    ADC_InitStructure.ADC_Mode
发表于 2022-01-12
AD转换汇总(<font color='red'>STM32</font>、取平均、过采样)
STM32单片机-低功耗设置
STM32F103R8和RC的停机模式的休眠电流还不一样,R8停机模式实测为11uA,RC停机模式实测为30uA,还以为又是我的程序哪里没做好呢,仔细看了PDF,这两个芯片PDF上标的值的确有区别,和我测的值差不多,那我就没有再深究的意义了! 结合下文的高手经验,反复摸索,standby模式1.9uA,PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);stop模式:11uA, PWR_EnterSTANDBYMode(); 实验证明,将IO端口设成IPU/IPD/AIN/PPOUT=1/PPOUT=0/ODOUT=0,电流是基本相同的,最可怕
发表于 2022-01-12
<font color='red'>STM32</font>单片机-低功耗设置
STM32单片机-操作访问内部Flash
目录:1、STM32 FLASH操作流程2、Flash基本知识点3、OK,上干货,上代码-------------------------------------------------------------------------------------------------STM32中存储区分为:随机存取存储器RAM和只读存储器ROM。 其中:RAM为常说的内存,比如手机的2G内存4G内存等,就是程序跑起来的时候所占用的存储空间,特点是掉电数据丢失。ROM为常说的硬盘,比如手机的64G和128G等,可以简单的理解为硬盘的存储空间,特点是掉电数据不丢失,所以又叫“非易失性存储器件”。 ROM又包含
发表于 2022-01-12
<font color='red'>STM32</font>单片机-操作访问内部Flash
STM32单片机-标准库编译成lib库
--------------------------------------------------------------------------------------------------------------------------------以前一直使用STM32的标准库,需要一步步地将代码加进去,将编译选项设置好,然后再编译整个工程。这个编译过程是一个相当慢的过程!完全编译大约需要一支烟的时间。每次建立工程都这么编译,是一个相当浪费时间和香烟的过程。于是,我有了将库编译成lib文件的想法。本博文就是我将STM32F4的标准库编译成lib文件并在工程中使用的过程。适用对象:1、熟悉库,不想再看库里边代码2、有稳定的库
发表于 2022-01-12
<font color='red'>STM32</font>单片机-标准库编译成lib库
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved