【STM32嵌入式蓝桥杯】1— LED流水灯逐个点亮然后逐个熄灭

一、赛制提供的开发板原理图:

        可以看出,原理图中有一个锁存器,只有引脚11(PD2)为高电平,2脚~9脚(1D~8D)的电平才能够赋值给12脚~19脚(1Q~8Q),否则,如果引脚11(PD2)为低电平,12脚~19脚(1Q~8Q)的电平会一直保存不表,可以理解为PD2锁住了LED1~8的电平。开发板电路这样设计一个锁存器在这里,是因为PC8~PC15有的引脚被LCD共用了。

        所以,要想点亮LED,比如LED1,需要先将PD2赋值高电平开锁,再给PC8赋值低电平,再将PD2赋值低电平锁住,此时1Q引脚就为低电平了,LED1点亮。

二、配置STM32CubeMX

选择单片机型号,然后点击开始项目

配置时钟,在System·Core的RCC处选择外部高速时钟源

选择调试接口和选择时钟基准

最后去 Clock Configuration时钟配置界面配置系统时钟频率,在HCLK 时钟那里输入 MCU 允许的最高时钟频率。配置成80Mhz,输入后按回车点击确认OK

命名工程、生成路劲

设置工程

以上的CubeMX的基本设置完成了,接下来就是设置需要使用的外设了,我们回到设置外设;

根据原理图,要想使用8个LED,与要用到PC8~PC15这8个IO口,同时需要设置锁存器,所以要配置PD2。

如下依次配置输出模式

如此都配置完成了,最后右上角点击生成代码(GENERATE CODE)即可。

三、构建代码框架

打开代码编译运行,我们会发现有报错:

My_Project\My_Project.axf: Error: L6218E: Undefined symbol HAL_PWREx_DisableUCPDDeadBattery (referred from stm32g4xx_hal_msp.o).
Not enough information to list image symbols.
Not enough information to list load addresses in the image map.
Finished: 2 information, 0 warning and 1 error messages.
"My_Project\My_Project.axf" - 1 Error(s), 1 Warning(s).

这是因为用了最新的Cube生成旧版的1.20固件库

解决办法:将错误往上滑,找到

../Core/Src/stm32g4xx_hal_msp.c(76): warning:  #223-D: function "HAL_PWREx_DisableUCPDDeadBattery" declared implicitly

然后双击会跳转,将76行的HAL_PWREx_DisableUCPDDeadBattery();改为HAL_PWREx_DisableUSBDeadBatteryPD();

修改后就不会了,如果固件库用的最新的就不会有这个问题。

然后我们打开我们的工程路径文件,新建一个我们自己的应用文件,这里我命名了APP

然后回到我们的工程将刚刚建立的文件添加到我们的工程中,右键My_Projectt添加新组

缓慢双击修改名称

添加文件路径到工程中,点击魔法棒按照下面步骤:

然后顺便设置烧录的驱动,驱动如果无法识别先解决这个,不然烧入不了

最后点击OK设置完成

接下来开始代码的编写,我的习惯是喜欢建立一个单独的模块驱动.c.h文件,如果是比赛时间怕不够的可以只建立一个。c文件就好了,全部塞那里去。

点击左上脚的新建文件

然后分别Ctrl+S保存命名,注意保存路径弄到我们刚才建立的那个文件里头

将.c文件添加到新组中,点击

在app.h下添加以下代码

#ifndef __APP_H
#define __APP_H



#endif /* __APP_H */

然后我们跳到main.c和app,c里,在注释有Begin和END之间添加app.h的头文件包含(主注意写在注释有Begin和END之间的那行,不然下次cubeMX重新生成会被清除)如下

将里面的头文件包含都复制到app.h里

编译无错误无警告后继续。代码框架的编写

在app.c里编写如下代码:

uint8_t dis=0;  /*利用这个标志,上电之后运行完对应的初始化后*/
/*-------------------------------------------------------------------------------------
 * 函数名称:Main_App
 * 函数功能:放在主函数的while(1)循环里,这样以后生成就不用动其他文件了。直接在这里操作
---------------------------------------------------------------------------------------*/
void Main_App(void)  /*主函数while(1)*/
{
	if(dis) /*循环的业务代码放这里*/
	{

	}
	else  /*只进来一次,放外设的初始化*/
	{
		dis=1;
	}
	
}

因为生成的代码很多那些注释,看的会很乱,所以就用了这种方式,尽量不动生成的代码

记得在app,h里声明函数,要放在主函数里的,如下位置

四、编写主要程序

编译无错误无警告之后,我们的代码框架就完成了,接下来开始点灯,直接附上整个app.c的代码:

#include "app.h"

uint8_t dis=0;  /*利用这个标志,上电之后运行完对应的初始化后*/
/*-------------------------------------------------------------------------------------
 * 函数名称:Main_App
 * 函数功能:放在主函数的while(1)循环里,这样以后生成就不用动其他文件了。直接在这里操作
---------------------------------------------------------------------------------------*/
void Main_App(void)  /*主函数while(1)*/
{
	uint8_t i;
	if(dis) /*循环的业务代码放这里*/
	{
		
		for(i=0;i<8;i++) /*依次点亮*/
		{
			LedCtrl(i,1);
			HAL_Delay(100);	
		}
		for(i=0;i<8;i++) /*依次熄灭*/
		{
			LedCtrl(i,0);
			HAL_Delay(100);	
		}
	}
	else  /*只进来一次,放外设的初始化*/
	{
		Led_PIN_SET();  /*熄灭所有LED*/
		dis=1;
	}
	
}

uint16_t GPIOC_ODR=0xFF00;  //两个FF对应的高位PC8~15
/*----------------------------------------------------------------------------------------------------
*函数名称:Led_PIN_SET()
*函数功能:流水灯全部置高电平
*输    入:无
*返 回 值:无
-----------------------------------------------------------------------------------------------------*/
void Led_PIN_SET(void)
{
	
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,0xff<<8,GPIO_PIN_SET);
	GPIOC_ODR=GPIOC->ODR;      //记录本次流水灯的点亮状态
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}


/*----------------------------------------------------------------------------------------------------
*函数名称:LedCtrl(uint8_t ds,uint8_t LED_State)
*函数功能:点亮和熄灭指定的LED灯
*输    入:ds:1~8,LED的位置,LED_State:0/1;0:指定的灯熄灭,1:指定的灯点亮
*返 回 值:无
*修 改 人:ZXP 2023/12/28 10:41
-----------------------------------------------------------------------------------------------------*/
void LedCtrl(uint8_t ds,uint8_t LED_State)
{
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);//开启锁存器的数据直通
	if(LED_State)
	{
		GPIOC->ODR |=0xFF00;   		            //熄灭所有led
		GPIOC->ODR &= ~(1<<(ds+7) | ~GPIOC_ODR); //保持上一个灯的状态,加7是为了移到高8位
		GPIOC_ODR=GPIOC->ODR;                    //记录本次流水灯的点亮状态
	}
	else if(!LED_State)
	{
		GPIOC->ODR |= (1<<(ds+7) | GPIOC_ODR); //熄灭指定的灯,或运算,1,加7是为了移到高8位
		GPIOC_ODR=GPIOC->ODR;                  //记录本次流水灯的点亮状态
	}
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);//锁存	
}

app,h

#ifndef __APP_H
#define __APP_H

#include "main.h"
#include "gpio.h"

void Main_App(void);
void Led_PIN_SET(void);
void LedCtrl(uint8_t ds,uint8_t LED_State);

#endif /* __APP_H */

效果,流水灯逐个点亮然后逐个熄灭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值