《STM32从零开始学习历程》——USART串口通讯实验篇2——指令控制LED灯实验

24 篇文章 1 订阅

《STM32从零开始学习历程》@EnzoReventon

USART串口通讯实验篇2——指令控制LED灯实验

本实验是在《USART串口通讯实验篇1——中断接收与发送》的基础上完成的,可以先学习实验1,然后再进行此实验,如果实验1能够理解并且处理的游刃有余,那么实验2将是小菜一碟了,本着从零开始的目的,我们还是一步一步,讲的详细一些。

1. 实验准备

软件:Keil μVision5 v5.33(MDK5),串口助手XCOM V2.6
环境:Windows10 Enterprise x64
芯片:STM32F406ZGT6
设备:正点原子STM32F4探索者开发板
仿真器:ST-Link
参考手册
[野火EmbedFire]《STM32库开发实战指南——基于野火霸天虎开发板》
[正点原子]STM32F4开发指南-库函数版本_V1.2
[ST]《STM32F4xx中文参考手册》
[ST]《STM32F407xx》

2. 实现功能

通过串口助手向STM32发送特定的指令,实现对LED灯的控制。
如:
发送字符“1”-----》LED1亮
发送字符“2”-----》LED2亮
发送字符“3”-----》LED1&LED2亮
发送字符“4”-----》LED1灭
发送字符“5”-----》LED2灭
发送字符“6”-----》LED1&LED2灭

3. 硬件设计流程

查阅开发板手册以及芯片手册非常重要!

  1. 根据实验1《USART串口通讯实验篇1——中断接收与发送》配置好USART通讯串口,本实验中,仍然使用USART1 PB6\PB7引脚。
  2. 查阅“正点原子”探索者F4开发板硬件电路,找到LED灯所对应的引脚。

在这里插入图片描述
在这里插入图片描述

小结:由硬件连接图与电路设计图可以看出,LED1与LED2连接于芯片的PF9与PF10端口,在软件设计时需要对这两个GPIO进行初始化设置。
由电路设计图可以看出,如果PF9与PF10端口为高电平(3.3V),则没有电压流过LED灯管,只有当PF9与PF10为低电平时才有电流流过LED灯管,因此只有使用GPIO_ResetBits()函数才可以点亮LED。

4. 程序设计流程

  1. 串口初始化时钟使能:RCC_APBxPeriphClockCmd();
    GPIO初始化时钟使能:RCC_AHBxPeriphClockCmd();
  2. 引脚复用映射:GPIO_PinAFConfig();
  3. GPIO端口模式配置:GPIO_Init();
  4. 串口参数初始化:USART_Init();
  5. 串口使能:USART_Cmd();
  6. 重定向printf与scanf函数;
  7. LED初始化:LED_Init();

5. 代码设计与分析

本实验设计分为三个部分:USART初始化子函数、LED初始化子函数,主函数。
1. 初始化USART

初始化USART串口函数:

void uart_init(u32 bound){
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;											//定义初始化结构体变量
	USART_InitTypeDef USART_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); 							//使能GPIOA时钟

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);							//使能USART1时钟
 
	//串口1对应引脚复用映射
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_USART1); 						//GPIOB6复用为USART1
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_USART1);							//GPIOB7复用为USART1
	
	//USART1端口配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; 							//GPIOB6与GPIOB7
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;									//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;								//速度50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 									//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 									//上拉

	GPIO_Init(GPIOB,&GPIO_InitStructure); 											//初始化PB6,PB7

    //USART1 初始化设置
	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
	
    USART_Cmd(USART1, ENABLE);  													//使能串口1 
	
}

重定向c库函数printf到串口,重定向后可使用printf函数:

在进行重定向函数编写时首先需要完成如下两个操作:
(1)在MDK5界面中点击“Options For Target”图标,将“USE MicroLIB”打上勾勾。在这里插入图片描述

(2)在定义文件中需要包含 #include “stdio.h” 头文件。

int fputc(int ch , FILE *f)
{
	USART_SendData(USART1,(uint8_t) ch );
																
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
																//USART_FLAG_TXE:发送数据寄存器中的数据有没有被取走
	return (ch);
}

重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数:

int fgetc(FILE *f)
{
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
																//USART_FLAG_TXE:发送数据寄存器中的数据有没有被取走
	return (int)USART_ReceiveData(USART1);
}

关于重定向函数的一些解释:

对于上文重定向printf、scanf与getchar函数读者可能对此有疑惑,故在此做一下说明。

重定向

就是指重新定义C库函数。对于printf()函数而言,printf只是一个宏定义,实际上调用的是fputc()函数,为了能够使用printf()函数直接向串口发送数据,需要重定向fputc()函数。同理,重定向scanf()函数也是这个意思。

FILE *f是单片机函数重定向的固定用法,因为C语言和单片机对fputc(),fgetc()函数的定义是不同的,在C中,标准的参数为int xxx , FILE *x,如果没有FILE *x 这个指针变量,则无法实现重定向,因此这是一个固定用法。
在定义函数时,FILE *x 这个指针变量必须有,但是函数主体中可以不使用。

2. 初始化LED

void LED_Init(void)
{    	 
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);										//使能GPIOF时钟

  //GPIOF9,GPIOF10初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;									//LED0和LED1对应IO口
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;												//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;											//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;										//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;												//上拉
  GPIO_Init(GPIOF, &GPIO_InitStructure);													//初始化GPIO
	
  GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);												//GPIOF9,F10设置高,灯灭
}

3. 主函数

对于主函数的编写比较清晰,先对串口、LED进行初始化调用,然后使用Switch对串口接收到的信息进行匹配,从而执行相应的动作。
此外还可以额外定义一个全局函数Show_Message()用来向串口发送提示信息。

static void Show_Message(void);																//函数申明

int main(void)
{
    char ch;																				//开辟一个字符存储空间
	delay_init(168);																		//延时初始化 
	uart_init(115200);																		//串口初始化波特率为115200
	LED_Init();		  																		//初始化与LED连接的硬件接口  
	Show_Message();																			//显示提示信息
	
	while(1)
	{
		ch = getchar();
		if(ch != '\0')
		{
		printf("接收到字符:%c\n",ch);
		}

		switch(ch)
		{
			case '1':
				GPIO_ResetBits(GPIOF,GPIO_Pin_9);  //LED0对应引脚GPIOF.9拉低,亮 ,等同LED0=0;
			break;
			
			case '2':
				GPIO_ResetBits(GPIOF,GPIO_Pin_10);  
			break;
			
			case '3':
				GPIO_ResetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);
			break;
			
			case '4':
				GPIO_SetBits(GPIOF,GPIO_Pin_9);
			break;
			
			case '5':
				GPIO_SetBits(GPIOF,GPIO_Pin_10);
			break;
			
			case '6':
				GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);
			break;
			
			default:
				Show_Message();
			break;
		}
	}
}

static void Show_Message(void)															//定义全局函数
{

	printf("\n 串口通讯控制实验: \n");
	printf("指令 -----------  跑马灯\n");
	printf("  1  -----------   LED1  ON \n");
	printf("  2  -----------   LED2  ON \n");
	printf("  3  -----------  LED1&2 ON \n");
	printf("  4  -----------   LED1  OFF \n");
	printf("  5  -----------   LED2  OFF \n");
	printf("  6  -----------  LED1&2 OFF \n");

}

6. 调试

编译,下载程序。
使用XCOM串口调试助手,会发现接收框不断地有Show_Message()中编写的提示信息发送过来。
在发送框中,输入3,点击发送。如下图所示,LED1&0被点亮,串口接收到指令3。

在这里插入图片描述
至此,试验结束。

7. 小结

其实本实验不难,是基于实验1进行了一些小改动而来的,主要是要了解下重定向。
有了此实验的基础,对于后期的实验或者工程会有很大的帮助。
如有不足之处还请各位大佬及时指出!

  • 6
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 首先,你需要连接一个LEDSTM32的一个引脚上,然后使用STM32串口模块来控制该引脚的电平状态。 下面是一个简单的示例代码: ```c #include "stm32f10x.h" #include "stdio.h" // 定义LED引脚 #define LED_PIN GPIO_Pin_13 #define LED_PORT GPIOC // 定义串口 #define USART USART1 #define USART_TX_PIN GPIO_Pin_9 #define USART_RX_PIN GPIO_Pin_10 void init_led(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIOC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 配置LED引脚为推挽输出 GPIO_InitStructure.GPIO_Pin = LED_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_PORT, &GPIO_InitStructure); } void init_usart(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 使能USART1和GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置USART1的TX引脚为复用推挽输出 GPIO_InitStructure.GPIO_Pin = USART_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART1的RX引脚为浮空输入 GPIO_InitStructure.GPIO_Pin = USART_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART1的参数 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(USART, &USART_InitStructure); // 使能USART1 USART_Cmd(USART, ENABLE); } int main(void) { char ch; // 初始化LEDUSART init_led(); init_usart(); while (1) { // 从串口读取一个字符 if (USART_GetFlagStatus(USART, USART_FLAG_RXNE) == SET) { ch = USART_ReceiveData(USART); // 如果收到字符 '1',则点LED if (ch == '1') { GPIO_SetBits(LED_PORT, LED_PIN); } // 如果收到字符 '0',则熄LED if (ch == '0') { GPIO_ResetBits(LED_PORT, LED_PIN); } } } } ``` 在该示例代码中,我们使用串口USART1来读取输入字符,并根据收到的字符控制LED。当接收到字符 '1' 时,点LED;当接收到字符 '0' 时,熄LED。 需要注意的是,在使用串口时,需要先初始化串口的GPIO引脚,然后配置串口的参数,最后使能串口。除此之外,还需要使用USART_GetFlagStatus()函数判断是否有数据可读,然后使用USART_ReceiveData()函数读取数据。 ### 回答2: 要使用STM32串口控制LED,可以按照以下步骤进行编程实现: 首先,在Keil等集成开发环境中创建一个新工程,并选择对应的STM32单片机型号。 然后,需要在代码中包含相应的头文件,包括对串口和GPIO的定义和配置。 接着,配置串口的波特率、数据位、停止位和校验位等参数,并初始化串口。 接下来,在代码中配置LED所连接的GPIO口,并设置该引脚为输出模式。 在主函数中,可以使用一个循环来不断接收串口数据并进行判断。当串口接收到特定的指令时,根据指令的内容控制LED。 在接收到控制指令后,可以使用if语句或switch语句来判断指令的具体内容。例如,当接收到字符"A"时,可以将LED引脚置高从而使LED起;当接收到字符"B"时,可以将LED引脚置低从而使LED。 最后,记得在循环中加入延时函数,以便观察LED效果。 需要注意的是,为了能够正确接收和发送串口数据,可能还需要配置中断和DMA等相关功能。 以上是使用STM32串口控制LED的基本步骤,具体的代码实现可以根据自己的需求灵活调整。 ### 回答3: STM32是一种广泛应用于嵌入式系统的微控制器,它可以通过串口控制LED串口是一种通信接口,可用于将数据发送或接收到外部设备。以下是如何使用STM32控制器和串口实现LED控制: 首先,需要配置STM32串口。选择合适的串口引脚作为发送和接收端口,并配置串口的波特率、校验位和停止位。 然后,编写STM32控制器的程序。在主程序中,通过串口接收数据。当接收到特定的命令时,根据命令设置相应的IO口来控制LED。 例如,当接收到字节“1”时,可以将LED所连接的IO口设置为高电平,从而使LED。当接收到字节“0”时,将IO口设置为低电平,从而使LED。 程序定期检查串口是否有新的数据到达,并根据接收到的数据执行相应的操作。这样,当用户通过串口发送特定的命令时,可以实现对LED控制。 需要注意的是,通过串口控制LED的前提是正确连接STM32LED,并正确配置引脚。此外,还需要确保串口接收的数据正确且互不冲突,以避免误操作。 通过以上步骤,我们可以利用STM32控制器和串口实现对LED控制。这种方法不仅简洁高效,而且灵活性强,可以根据需要对LED进行灵活的控制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EnzoReventon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值