串口通信实验(通过串口控制LED、蜂鸣器)

2023-05-16

需要添加的固件库文件有 stm32f4xx_gpio.c、stm32f4xx_rcc.c、 misc.c、 stm32f4xx_usart.c 四个。

1) 串口时钟和 GPIO 时钟使能。
串口3是挂载在 APB1 下面的外设,, 对应着芯片引脚 PB10、PB11,所以使能函数为:

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能 GPIOB 时钟
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);//使能 USART3 时钟 

2) 设置引脚复用器映射
引脚复用器映射配置,调用函数为:

GPIO_PinAFConfig(GPIOB,GPIO_PinSource10, GPIO_AF_USART3);		// //PB10 复用为 USART3
GPIO_PinAFConfig(GPIOB,GPIO_PinSource11, GPIO_AF_USART3);   // //PB11 复用为 USART3 

因为串口使用到 PB10,PB11,所以我们要把 PB10 和PB11 都映射到串口3。所以这里调用两次函数。 对于 GPIO_PinAFConfig 函数的第一个和第二个参数很好理解,就是设置对应的 IO 口,如果是 PB10那么第一个参数是GPIOB,第二个参数就是 GPIO_PinSource10。第二个参数,实际不需要去记忆,只需去相应的配置文件找到外设对应的 AF 配置宏定义标识符即可,串口 3为 GPIO_AF_USART3。

3) GPIO 端口模式设置: PB10,PB11 要设置为复用功能。

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 |GPIO_Pin_11;  //PB10 PB11
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;  //复用模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;  //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;		//上拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //速度50MHz
	GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化

4) 串口参数初始化并使能:设置波特率,字长,奇偶校验等参数
串口初始化是调用函数 USART_Init 来实现的,具体设置方法如下:

    USART_InitStructure.USART_BaudRate=bound;  //设置波特率
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;//收发模式 
	USART_InitStructure.USART_Parity= USART_Parity_No;//无奇偶校验位 
	USART_InitStructure.USART_StopBits= USART_StopBits_1;//一个停止位 
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长为 8 位数据格式 
	USART_Init(USART3, &USART_InitStructure); //初始化串口 
	USART_Cmd(USART3, ENABLE);  //使能串口3 

5) 开启中断并且初始化 NVIC,使能相应中断
这一步如果我们要开启串口中断才需要配置 NVIC 中断优先级分组。通过调用函数NVIC_Init 来设置。

    NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;  //响应优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ 通道使能 
	NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器

同时,我们还需要使能相应中断,使能串口中断的函数是:

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

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

USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断 

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

USART_ITConfig(USART1,USART_IT_TC,ENABLE); 

这里还要特别提醒,因为实验开启了串口中断,所以在系统初始化的时候需要先设置系统的中断优先级分组,是在main 函数开头设置的,代码如下:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2

设置分组为 2,也就是 2 位抢占优先级,2 位响应优先级。

6) 中断服务函数
当发生中断的时候,程序就会执行中断服务函数。然后在中断服务函数中编写我们相应的逻辑代码即可。

void USART3_IRQHandler(void)  
{
	u8 rec_data;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断 
		{
				rec_data =(u8)USART_ReceiveData(USART3);         //(USART3->DR) 读取接收到的数据
        if(rec_data=='S')		  	                         //如果是S,表示是命令信息的起始位
				{
					uart_byte_count=0x01; 
				}

			else if(rec_data=='E')		                         //如果E,表示是命令信息传送的结束位
				{
					if(strcmp("Light_led1",(char *)receive_str)==0)        LED1=0;	//点亮LED1
					else if(strcmp("Close_led1",(char *)receive_str)==0)   LED1=1;	//关灭LED1
					else if(strcmp("Open_beep",(char *)receive_str)==0)    BEEP=1; 	//蜂鸣器响
					else if(strcmp("Close_beep",(char *)receive_str)==0)   BEEP=0; 	//蜂鸣器不响
					
					for(uart_byte_count=0;uart_byte_count<32;uart_byte_count++)receive_str[uart_byte_count]=0x00;//数组清零
					uart_byte_count=0;    
				}				  
			else if((uart_byte_count>0)&&(uart_byte_count<=USART3_REC_NUM))
				{
				   receive_str[uart_byte_count-1]=rec_data;
				   uart_byte_count++;
				}                		 
   } 
} 

7) 软件设计
usart.c 代码

#include "common.h"
#include "beep.h"
#include "led.h"
#include "usart3.h"
#include "string.h"
#include "stdlib.h"

/*********************************************************************************
************************STM32F407核心开发板******************************
**********************************************************************************
* 文件名称: usart3.c                                                             *
* 文件简述:USART3使用                                                           *
* 创建日期:2020.08.12                                                           *
* 版    本:V1.0                                                                 *
* 作    者:近视未看清人心                                                              *
* 说    明:利用串口调试助手经过USART1控制LED亮灭与蜂鸣器响闭                    * 
**********************************************************************************
*********************************************************************************/	


u8 receive_str[USART3_REC_NUM];     //接收缓存数组,最大USART_REC_LEN个字节 
u8 uart_byte_count=0;

/****************************************************************************
* 名    称: void uart3_init(u32 bound)
* 功    能:USART3初始化
* 入口参数:bound:波特率
* 返回参数:无
* 说    明: 
****************************************************************************/

void uart3_init(u32 bound)
{

	GPIO_InitTypeDef  GPIO_InitStructure;		//声明一个io初始化结构体变量
	NVIC_InitTypeDef NVIC_InitStructure;		//声明一个中断分组初始化结构体变量
	USART_InitTypeDef USART_InitStructure;		//声明一个窗口初始化结构体变量

	//使能时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能 GPIOB 时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);//使能 USART3 时钟 

	//设置引脚复用
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource10, GPIO_AF_USART3);		// //PB10 复用为 USART3
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource11, GPIO_AF_USART3);   // //PB11 复用为 USART3 
	
	//配置GPIO
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 |GPIO_Pin_11;  //PB10 PB11
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;  //复用模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;  //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;		//上拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //速度50MHz
	GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化
	
	//串口参数配置
	USART_InitStructure.USART_BaudRate=bound;  //设置波特率
	USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;//收发模式 
	USART_InitStructure.USART_Parity= USART_Parity_No;//无奇偶校验位 
	USART_InitStructure.USART_StopBits= USART_StopBits_1;//一个停止位 
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长为 8 位数据格式 
	USART_Init(USART3, &USART_InitStructure); //初始化串口 
	USART_Cmd(USART3, ENABLE);  //使能串口3 
	
	//NVIC 设置,使能中断 
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断 
	
	NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;  //响应优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ 通道使能 
	NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器
	
	 

}

//串口3发送一个字符
void uart3SendChar(u8 ch)
{      
	while((USART3->SR&0x40)==0);  
    USART3->DR = (u8) ch;      
}

/****************************************************************************
* 名    称: int fputc(int ch, FILE *f)
* 功    能:重定向,让printf输出到串口  
* 入口参数:
* 返回参数:
* 说    明:因printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法
            运行,以下是解决方法:使用微库,因为使用微库的话,不会使用半主机模式. 
            请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB“这
            样以后就可以使用printf,sprintf函数了  
****************************************************************************/
int fputc(int ch, FILE *f)   //重定向,让printf输出到串口  
{
    uart3SendChar(ch);
    while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
	
    return ch;
}

/****************************************************************************
* 名    称: void uart3SendChars(u8 *str, u16 strlen)
* 功    能:串口3发送一字符串
* 入口参数:*str:发送的字符串
            strlen:字符串长度
* 返回参数:无
* 说    明: 
****************************************************************************/
void uart3SendChars(u8 *str, u16 strlen)
{ 
	  u16 k= 0 ; 
   do { uart3SendChar(*(str + k)); k++; }   //循环发送,直到发送完毕   
    while (k < strlen); 
} 

//串口3中断服务程序
void USART3_IRQHandler(void)  
{
	u8 rec_data;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断 
		{
				rec_data =(u8)USART_ReceiveData(USART3);         //(USART3->DR) 读取接收到的数据
        if(rec_data=='S')		  	                         //如果是S,表示是命令信息的起始位
				{
					uart_byte_count=0x01; 
				}

			else if(rec_data=='E')		                         //如果E,表示是命令信息传送的结束位
				{
					if(strcmp("Light_led1",(char *)receive_str)==0)        LED1=0;	//点亮LED1
					else if(strcmp("Close_led1",(char *)receive_str)==0)   LED1=1;	//关灭LED1
					else if(strcmp("Open_beep",(char *)receive_str)==0)    BEEP=1; 	//蜂鸣器响
					else if(strcmp("Close_beep",(char *)receive_str)==0)   BEEP=0; 	//蜂鸣器不响
					
					for(uart_byte_count=0;uart_byte_count<32;uart_byte_count++)receive_str[uart_byte_count]=0x00;//数组清零
					uart_byte_count=0;    
				}				  
			else if((uart_byte_count>0)&&(uart_byte_count<=USART3_REC_NUM))
				{
				   receive_str[uart_byte_count-1]=rec_data;
				   uart_byte_count++;
				}                		 
   } 
} 

usart.h 代码

#ifndef __USART3_H
#define __USART3_H
#include "stdio.h"	
#include "common.h" 

//	 

#define USART3_REC_NUM  			100  	//定义最大接收字节数 200
extern u8 uart_byte_count;          //uart_byte_count要小于USART_REC_LEN
extern u8 receive_str[USART3_REC_NUM];  

void uart3_init(u32 bound);
void uart3SendChars(u8 *str, u16 strlen);

#endif

main.c 代码

#include "usart3.h"
#include "led.h"
#include "beep.h"
#include "key.h"


/*********************************************************************************
*********************STM32F407应用开发板(高配版)*************************
**********************************************************************************
* 文件名称: USART3命令控制主函数main.c                                     *
* 文件简述:USART3命令控制使用                                                   *
* 创建日期:2020.08.12                                                           *
* 版    本:V1.0                                                                 *
* 作    者:Clever                                                               *
* 说    明:利用串口调试助手经过USART1控制LED亮灭与蜂鸣器响闭,按KEY0串口发送数  *
            据到串口调试助手                                                     *                                      *
* 声    明:本例程代码仅用于学习参考                                             *
**********************************************************************************
*********************************************************************************/

int main(void)
{   
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2
	delay_init();		      //延时初始化 
	uart3_init(9600);	    //串口初始化波特率为9600
	KEY_Init();
	LED_Init();		  		  //初始化与LED 
	BEEP_Init();          //蜂鸣器初始化
	LED0=0;
	while(1)
	{
		key_scan(0);
		
		if(keyup_data==KEY0_DATA)
		  {
		    /*因printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法
          运行,以下是解决方法:使用微库,因为使用微库的话,不会使用半主机模式. 
          请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB“这
          样以后就可以使用printf,sprintf函数了*/
				printf("串口打印测试\r\n");
				uart3SendChars("UART1 TEST\r\n",13);
				LED0=!LED0;
		  }
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

串口通信实验(通过串口控制LED、蜂鸣器) 的相关文章

  • 利用MQTT协议与阿里云数据交互的python程序

    利用MQTT协议与阿里云数据交互的python程序 设计目的功能要求和关键问题环境配置问题本地程序如何连接云上设备云上的数据交互问题界面设计问题 阿里云相关操作本地程序 设计目的 设计开发一个py应用程序 xff0c 实现对阿里云数据的双向
  • 中文分词:隐马尔可夫-维特比算法(HMM-Viterbi)附源码

    目录 0 先验知识 1 什么是中文分词 2 数据集的构造 3 训练及预测过程简述 4 训练阶段 xff1a 统计隐马尔可夫模型的参数 5 预测阶段 xff1a 应用 Viterbi 算法 6 完整的 Python 实现代码 0 先验知识 有
  • python学习day1

    打印字 print haha 注释符 单行注释符 xxx 多行注释符 xxx xxx 34 34 定义变量 a 61 10 定义数字 b 61 haha ni hao 定义字符串 print a print b 赋值 b 61 a 用户交互
  • 系统学习-----firewalld概述

    动态防火墙后台服务程序 xff1a 提供一个动态管理的防火墙 xff0c 用以支持网络 Zone xff0c 来分配对一个网络链接和界面一定程序的信息 xff0c 它具备对IPv4和Ipv6防火墙设置的支持 它支持以太网桥 xff0c 并有
  • 系统学习----DHCP服务原理

    文章目录 DHCPDHCP优点DHCP相关概念DHCP租约更新DHCP运行过程 DHCP DHCP xff1a 动态主机设置协议 xff0c 是一个局域网协议 xff0c 使用UDP协议工作 主要有两个用途 xff1a 用于局域网或网络服务
  • 区块链技术及应用---区块链技术(一)

    文章目录 第一章 疯狂的比特币及其原理机制1 1 比特币诞生1 2 疯狂的比特币1 2 1 疯狂的价格1 2 2 疯狂的矿机和芯片 1 3 通俗地讲比特币机制1 4比特币交易1 5 比特币挖矿1 5 1 数学难题1 5 2 矿池原理 1 6
  • OpenFlow协议是什么

    为什么学习OpenFlow xff1f 实践SDN的首选主流南向接口协议P4和PISA的前身 OpenFlow起源 Ethane项目是OpenFlow的前身 集中式 主动式 xff0c 基于Flow控制2008年的Open Flow论文最初
  • OpenDaylight(ODL)学习笔记

    什么是OpenDaylight xff1f OpenDaylight是SDN开发及运行的一个平台 OpenDaylight架构特点 基于OSGi的模块化设计多南向协议 OpenFlow xff0c Netconf xff0c OVSDB 模
  • Vue / axios / props 调用后端接口数据并渲染到页面

    情景介绍 给了一个可视化大屏的代码 xff0c 代码上写的是假数据 现在要调用后端接口获取数据 xff0c 并将其渲染到页面上 分析问题 给的代码是一个 vue 组件嵌套一个子组件 xff0c 要把数据渲染到子组件上 要调用后端接口 xff
  • Element-ui关于el-icon无法正常显示的问题(已解决)

    在使用element ui组件库的时候 xff0c 使用自带的图标不显示 xff0c 查了好多篇博客 xff0c 都说是element ui的版本老了 xff0c 在package json中修改版本重新安装就行 xff0c 但是我的情况不
  • el-dialog关闭后表单数据缓存没清空【已解决】

    情景介绍 系统中有 新增 和 修改 两个功能 xff0c 共用一个对话框 要求新增时对话框内容为空 xff0c 修改时内容默认填充旧数据 遇到的问题是 xff0c 点击新增后内容填充了 xff0c 关闭对话框再点击新增或者其他条目的修改 x
  • Vue中父组件向子组件传值,子组件没有接收到

    情景介绍 父组件调用接口获取数据 xff0c 然后通过props传值给子组件 xff0c 子组件拿到数据后渲染到 el table 表格组件中 结果子组件没有将数据渲染到表格中 xff0c 但是控制台打印是获取到数据的 问题分析 先看父组件
  • 数字通信系统的性能及可靠性

    目录 1 数字通信系统的性能 2 数字通信系统的可靠性 1 数字通信系统的性能 数字通信系统的性能由码元速率 信息速率 频带利用率表示 每个码元所携带的信息量I定义如下 xff1a 这里 P 是每个码元的概率 xff0c M 是码元的个数
  • 前端学习资源分享

    学习资源 编程导航 xff08 包含以下所有资源 xff0c 强烈推荐 x1f44d xff09 xff1a https www code nav cn freeCodecamp 在线编程 xff1a https learn freecod
  • 嵌入式方向分析

    很多计算机 电子信息类专业的学生都想把嵌入式开发作为自己的职业目标 xff0c 但是因为嵌入式涉及的知识太多 xff0c 太杂 xff0c 太广 xff0c 很多嵌入式初学者陷入嵌入式知识的海洋中 xff0c 东学一点 xff0c 西学一点
  • UWB-DW1000初始化、发送和接收详解(一)

    DWM1000简介 DWM1000板子上的DW1000芯片 xff0c 是基于CMOS的 低功耗的无线收发集成电路 xff0c 遵循IEEE 802 15 4 2011协议中的UWB标准芯片 DWM1000不需要用户去设计电路 xff0c
  • 云计算-弹性存储

    云盘 挂载到ECS上的磁盘 NAS 文件存储 OSS 对象存储 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img 1NMdcten 1653882562436 https files mdnice com user
  • computers & security投稿教程

    在computers amp security上投稿了一篇论文 xff0c 中间还是遇到一些不太懂的东西 xff0c 在此记录下来 1 首先打开官网 xff0c 链接 https www editorialmanager com cose
  • 【SDN测试题】

    SDN测试题 一 判断题 NFV与SDN的基础都是通用服务器 云计算以及虚拟化技术 正确答案 xff1a 对 安装OpenvSwitch时必须根据系统内核版本选择相应的Open vSwitch版本 正确答案 xff1a 对 执行命令ovs
  • 【阅读论文】基于VAE-LSTM混合模型的时间序列异常检测

    Anomaly Detection for Time Series Using VAE LSTM Hybrid Model CCFB Shuyu LinRonald ClarkRobert BirkeSandro Sch nbornNiki

随机推荐