基于STM32F103ZET6库函数串口实验

  • 本次实验实现如下功能
  • 串口设置的一般步骤可以总结为如下几个步骤
  • 与串口基本配置直接相关的几个固件库函数
    • 1.串口时钟使能。
    • 2.串口复位。
    • 3.串口参数初始化。
    • 4..数据发送与接收。
    • 5.串口状态。
    • 6.串口使能。
    • 7.开启串口响应中断。
    • 8.获取相应中断状态。
  • 硬件设计
  • 软件设计

本次实验实现如下功能

STM32F1 通过串口和上位机的对话,STM32F1 在收到上位机发过来的字符串后,原原本本的返回给上位机。

接下来主要从库函数操作层面结合寄存器的描述,告诉你如何设置串口,以达到最基本的通信功能。 利用串口 1 不停的打印信息到电脑上,同时接收从串口发过来的数据,把发 送过来的数据直接送回给电脑。通过 USB 串口和电脑通信。

串口设置的一般步骤可以总结为如下几个步骤

  1. 串口时钟使能,GPIO 时钟使能
  2. 串口复位
  3. GPIO 端口模式设置
  4. 串口参数初始化
  5. 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
  6. 使能串口
  7. 编写中断处理函数

与串口基本配置直接相关的几个固件库函数

这些函数和 定义主要分布在 stm32f10x_usart.h 和 stm32f10x_usart.c 文件中。

1.串口时钟使能。

串口是挂载在 APB2 下面的外设,所以使能函数为:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);

2.串口复位。

当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置 这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外 设的操作。复位的是在函数 USART_DeInit()中完成:

void USART_DeInit(USART_TypeDef* USARTx);//串口复位

3.串口参数初始化。

串口初始化是通过 USART_Init()函数实现的

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

这个函数的第一个入口参数是指定初始化的串口标号,这里选择 USART1。
第二个入口参数是一个 USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用 来设置串口的一些参数。一般的实现格式为:

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);                                           //初始化串口 

4…数据发送与接收。

STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是 一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收 到数据的时候,也是存在该寄存器内。
STM32 库函数操作 USART_DR 寄存器发送数据的函数是:
通过该函数向串口寄存器 USART_DR 写入一个数据。

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

5.串口状态。

在我们固件库函数里面,读取串口状态的函数是:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的 RXNE(读数据寄存器非空)以及 TC(发送完成)。
例如我们要判断读寄存器是否非空(RXNE),操作库函数的方法是:

USART_GetFlagStatus(USART1, USART_FLAG_RXNE);

我们要判断发送是否完成(TC),操作库函数的方法是:

USART_GetFlagStatus(USART1, USART_FLAG_TC);

这些标识号在 MDK 里面是通过宏定义定义的:

#define USART_IT_PE                          ((uint16_t)0x0028)
#define USART_IT_TXE                         ((uint16_t)0x0727)
#define USART_IT_TC                          ((uint16_t)0x0626)
#define USART_IT_RXNE                        ((uint16_t)0x0525)
#define USART_IT_IDLE                        ((uint16_t)0x0424)
#define USART_IT_LBD                         ((uint16_t)0x0846)
#define USART_IT_CTS                         ((uint16_t)0x096A)
#define USART_IT_ERR                         ((uint16_t)0x0060)
#define USART_IT_ORE                         ((uint16_t)0x0360)
#define USART_IT_NE                          ((uint16_t)0x0260)
#define USART_IT_FE                          ((uint16_t)0x0160)

6.串口使能。

串口使能是通过函数 USART_Cmd()来实现的

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

7.开启串口响应中断。

有些时候当我们还需要开启串口中断,那么我们还需要使能串口中 断,使能串口中断的函数是:

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

这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类 型有很多种。比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断,那么我 们开启中断的方法是:

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断

我们在发送数据结束的时候(TC,发送完成)要产生中断,那么方法是:

USART_ITConfig(USART1,USART_IT_TC,ENABLE);

8.获取相应中断状态。

当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄 存器中的某个标志位。经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)

比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这 个函数来判断到底是否是串口发送完成中断,方法是:

USART_GetITStatus(USART1, USART_IT_TC)

返回值是 SET,说明是串口发送完成中断发生。

硬件设计

1) 指示灯 DS0
2) 串口 1
本实验用到的串口 1 与 USB 串口并没有在 PCB 上连接在一起, 需要通过跳线帽来连接一下。这里我们把 P3 的 RXD 和 TXD 用跳线帽与 PA9 和 PA10 连接起来。

软件设计

//初始化 IO 串口 1
void uart_init(u32 bound)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;/*1.使能USART1,GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);    /*2.串口复位,这里没有 *//*3.GPIO 端口模式设置 *///USART1_TX   GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                    //PA.9GPIO_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;                    //PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);                        //初始化GPIOA.10  /*4.串口参数初始化 *///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/*5.初始化 NVIC *///Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;                          //抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                                 //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                     //IRQ通道使能NVIC_Init(&NVIC_InitStructure);                                                        //根据指定的参数初始化VIC寄存器/*5.开启中断 */USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                     //开启串口接受中断/*6.使能串口 */USART_Cmd(USART1, ENABLE);                                                         //使能串口1 }

① 串口时钟使能,GPIO 时钟使能
② 串口复位
③ GPIO 端口模式设置
④ 串口参数初始化
⑤ 初始化 NVIC 并且开启中断
⑥ 使能串口

usart.c

#include "sys.h"
#include "usart.h"      //标准库需要的支持函数
struct __FILE
{ int handle;
};
FILE __stdout;       //重定义fputc函数
int fputc(int ch, FILE *f)
{      while((USART1->SR&0X40)==0){;                                                                           //循环发送,直到发送完毕   }USART1->DR = (u8) ch;      return ch;
} #if EN_USART1_RX                                                                      //如果使能了接收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_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.9GPIO_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;                                     //PA.10GPIO_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 ;                      //抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                             //子优先级3NVIC_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);                                         //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                  //开启串口接收中断USART_Cmd(USART1, ENABLE);                                                        //使能串口1 }/*串口1中断服务程序*/
void USART1_IRQHandler(void)
{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;                                              //接收数据错误,重新开始接收}}        }}          }
}
#endif  

如果EN_USART1_RX等于1下面代码就执行
定义缓冲区和接收状态标记,接收标记为16位
0到13位为接收到的有效数目
14位为接收到0x0d的标记
15位为接收到0x0a的标记(即接收完成)

串口初始化这里按着步骤配置就好

下面来说一下串口1的中断服务函数

第一步读取接收的数据存到Res(这里是8位,每8位接收一次)
第二步如果还没读到0x0d就存进缓冲区USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;
USART_RX_STA&0X3FFF,这里限制只有用到0到13位
if(USART_RX_STA>(USART_REC_LEN-1))这里也限制了缓冲区的大小
第三步如果读到了0x0d就改变14位的状态USART_RX_STA|=0x4000;让14位置1
第四步接收到0x0d下一位就判断是否是0x0a,如果是就改变15位的状态USART_RX_STA|=0x8000;让15位置1,即接收完成

这里还有一个重定向函数int fputc(int ch, FILE *f)
此函数原本是将字符ch打印到文件指针stream所指向的文件流去的,现在我们不需要打印到文件流,而是打印到串口1

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       //使能(1)/禁止(0)串口1接收extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA;                //接收状态标记    void uart_init(u32 bound);
#endif

extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
extern声明给其它的文件使用这些变量

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;delay_init();                                                                              //延时函数初始化     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                           //设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(115200);                                                                          //串口初始化为115200LED_Init();                                                                                   //LED端口初始化KEY_Init();                                                                               //初始化与按键连接的硬件接口while(1){if(USART_RX_STA&0x8000){                       len=USART_RX_STA&0x3fff;                                                            //得到此次接收到的数据长度printf("\r\n您发送的消息为:\r\n\r\n");for(t=0;t<len;t++){USART_SendData(USART1, USART_RX_BUF[t]);                                        //向串口1发送数据while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);                           //等待发送结束}printf("\r\n\r\n");                                                                  //插入换行USART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\n串口实验\r\n");printf("是北豼不太皮吖\r\n\r\n");}if(times%200==0){printf("请输入数据,以回车键结束,或勾上发送新行\r\n");}if(times%30==0){LED0=!LED0;                                                                     //闪烁LED,提示系统正在运行.}delay_ms(10);   }}
}

if(USART_RX_STA&0x8000)判断是否接收完成
如果接收完成就把数据发回去
USART_RX_STA为传过来实际的字节数
len=USART_RX_STA&0x3fff;这里把14,15位的标记位去掉

基于STM32F103ZET6库函数串口实验相关推荐

  1. 基于STM32F103ZET6库函数外部中断实验

    基于STM32F103ZET6库函数外部中断实验 外部中断简介 IO 口外部中断的一般步骤 软件设计 外部中断简介 通过板载的 3 个按键,控制板载的两个 LED 的亮灭以及蜂鸣器的发声. 代码主要分 ...

  2. 基于STM32F103ZET6库函数PWM输出实验

    基于STM32F103ZET6库函数PWM输出实验 PWM 简介 硬件设计 软件设计 使 用 TIM3 的通道 2,把通道 2 重映射到 PB5,产生 PWM 来控制 DS0 的亮度. PWM 简介 ...

  3. 基于STM32F103ZET6库函数定时器中断实验

    基于STM32F103ZET6库函数定时器中断实验 STM32F1 通用定时器简介 定时器相关的库函数主要集中在固件库文件 stm32f10x_tim.h 和 stm32f10x_tim.c 文件中 ...

  4. 基于STM32F103ZET6库函数按键输入实验

    基于STM32F103ZET6库函数按键输入实验 GPIO_ReadInputDataBit函数 硬件设计 软件设计 我们将通过 ALIENTEK 精英 STM32F103 上载有的 3 个按钮(KE ...

  5. FPGA入门实验-基于状态机实现串口回环收发

    任务目标 基于状态机实现串口回环收发.最近生产实习的FPGA培训课程内容,还是挺简单的.具体原理其他文章应该都烂大街了,重点是状态机的写法,还是很少博主写,没怎么看到,基本上都是时序机写的模块功能. ...

  6. 基于FPGA Uart串口通信实验

    基于FPGA Uart串口通信实验 首先需要了解uart串口通信协议,根据个人专业需求不同,了解的层面可以不同. UART简介 通用异步收发传输器(Universal Asynchronous Rec ...

  7. 基于标准库函数与基于HAL库函数的stm32编程方式

    文章目录 基于标准库函数与基于HAL库函数的stm32编程方式 一.基于标准库 1. 介绍 2. 库函数的STM32串口程序编写 二.基于HAL库 1.介绍 2.HAL库STM32串口程序编写 三.差 ...

  8. 基于标准库函数与基于HAL库函数的stm32编程方式对比

    基于标准库函数与基于HAL库函数的stm32编程方式对比 一.标准库函数 二.HAL库函数 三.差异 四.stdunio IDE试玩 参考资料 一.标准库函数 1.标准库的解释 标准外设库(Stand ...

  9. STM32之USART-串口通信(含串口实验详细解析)

    STM32之串口通信 - USART(含串口实验详细解析) 开发环境:Window 10 开发工具:Keil uVision5 MDK 硬件:STM32F103 资料参考: [正点原子]STM32F1 ...

最新文章

  1. 二叉搜索树的简明实现(ES5 ES6)
  2. android gpio驱动实例,Android/Linux 驱动层对GPIO口的操作方法和相关代码
  3. git 版本操作命令大全
  4. android 保存流媒体,Android实现使用流媒体播放远程mp3文件的方法
  5. Centos7 释放内存
  6. SAP Fiori Elements - When is catalog annotation $value loaded
  7. zookeeper介绍及集群的搭建(利用虚拟机)
  8. 互联网日报 | 2月23日 星期二 | 华为发布新一代折叠旗舰Mate X2;字节跳动游戏官网正式上线;携程设立轮值制度...
  9. sharepoint_study_5
  10. python 注销一大段_Django框架用户注销功能实现方法分析
  11. android 字体加粗_Android小技巧之TextView字体加粗
  12. 微型计算机汇编用什么软件,EMU8086 汇编工具软件的使用
  13. 使用REG注册表文件添加、修改或删除注册表键值和子项介绍
  14. android关闭触摸提示音,修改Android系统的触摸提示音【学习笔记】
  15. Java常见练习题总结
  16. Cloudera Manager 5升级(官方翻译整理,企业级实战验证)
  17. 将电脑文件夹内的文件名批量导入到Excel表格中
  18. 关于学生管理系统(注册,登录,学生端)
  19. 多个lmg在盒子里在左浮动( float: left)时候出现横向图片中间有缝隙
  20. svg文件解析(python)

热门文章

  1. 一文教你如何用Python读取图片GPS定位
  2. java 第八周的选做题
  3. 【转】Android 手机连接台式电脑无线 Wi-Fi 上网
  4. Android——动态设置view背景颜色setBackgroundColor
  5. cozmo玩耍记录1
  6. also的位置情况总结(基于材料:“老托福听力93篇”)
  7. 走计算机这条路的第一个10月24
  8. jacob 抽取word文档
  9. 阿里云林小平:如何实现资源高效运维及成本分析
  10. hnust 2022汇编语言期中考试笔记