文章目录
相关说明:
开发板:CT117E-M4(STM32G431RB 蓝桥杯嵌入式比赛板)
开发环境: CubeMX+Keil5
涉及题目:第十四届蓝桥杯嵌入式模拟题2
题目难点:难度相对较低
题目来源:4T
CubeMX配置、主要函数代码及说明:
1.使能外部高速时钟:

2.配置时钟树:

3.GPIO:

4.TIM2(PA1输出):

5.TIM3(同上,PA7输出):

6.TIM6(控制LED闪烁):

7.TIM7(判断串口接收,同上,5ms中断):

8.NVIC(输入捕获中断配置):
main.c
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//输入捕获中断函数 计算输入信号频率
void LCD_Init_Show(void); //LCD初始化显示
void LCD_Refresh(void); //LCD更新显示
gpio.h
void KEY_Scan(void);//按键扫描
void LED_AllClose(uint8_t *LED_Close);//LED更新显示
void LED_Change(void);//LED状态改变
adc.h
double ADC_GetValue(void);//获取R37电压值
time.h
void PWM_Out(double R37_V,uint32_t FRQ,uint8_t R);//PWM输出
在CubeMX中可以配置User Label选项即可生成对应宏定义
生成宏定义:
main.h
#define LED6_Pin GPIO_PIN_13
#define LED6_GPIO_Port GPIOC
#define LED7_Pin GPIO_PIN_14
#define LED7_GPIO_Port GPIOC
#define LED8_Pin GPIO_PIN_15
#define LED8_GPIO_Port GPIOC
#define KEY4_Pin GPIO_PIN_0
#define KEY4_GPIO_Port GPIOA
#define KEY1_Pin GPIO_PIN_0
#define KEY1_GPIO_Port GPIOB
......此处省略
自定义宏定义(灯的控制,PD2引脚控制):
main.h
#define OFF GPIO_PIN_SET
#define ON GPIO_PIN_RESET
#define LED1(a) HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,a)
#define LED2(a) HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,a)
#define LED3(a) HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,a)
#define LED4(a) HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,a)
#define LED5(a) HAL_GPIO_WritePin(LED5_GPIO_Port,LED5_Pin,a)
#define LED6(a) HAL_GPIO_WritePin(LED6_GPIO_Port,LED6_Pin,a)
#define LED7(a) HAL_GPIO_WritePin(LED7_GPIO_Port,LED7_Pin,a)
#define LED8(a) HAL_GPIO_WritePin(LED8_GPIO_Port,LED8_Pin,a)
#define LED_All(a) HAL_GPIO_WritePin(LED8_GPIO_Port,GPIO_PIN_All,a)
#define LOCK_HIGH() HAL_GPIO_WritePin(LOCK_GPIO_Port,LOCK_Pin,GPIO_PIN_SET)
#define LOCK_LOW() HAL_GPIO_WritePin(LOCK_GPIO_Port,LOCK_Pin,GPIO_PIN_RESET)
char buf[20]; //字符串拼接数组
uint8_t LED[4] = {1,0,1,0}; //LED状态数组
uint16_t PA7_HZ = 1000; //PA7输出信号频率
uint8_t PA7_D = 10; //PA7输出信号占空比
uint16_t PA1_HZ = 1000; //PA1输出信号频率
uint8_t PA1_D = 10; //PA1输出信号占空比
uint8_t page = 1; //page1:PA1数据页 page2:PA7数据页
uint8_t rec_byte; //串口数据存储
uint8_t mode = 1; //当前模式 1:按键控制 0:串口控制
uint8_t rec_flag = 0; //串口接收标志位
uint16_t rec_num = 0; //串口一次接收字节数
此处将按键按下后的操作都封装成独立的函数调用:
KEY1 – 改变频率
KEY2 – 改变占空比
KEY3 – 数据页改变
KEY4 – 操作模式改变
void KEY_Process()
{
if((HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET))
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
HZ_Change();//频率改变
while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
D_Change();//占空比改变
while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin) == GPIO_PIN_RESET && (mode == 1))
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin) == GPIO_PIN_RESET)
{
Page_Change();//数据页改变
while(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin) == GPIO_PIN_RESET);
}
}
else if(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin) == GPIO_PIN_RESET)
{
Mode_Change();//模式改变
while(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin) == GPIO_PIN_RESET);
}
}
}
输出信号频率、占空比、数据页以及操作模式改变
/*相关变量*/
uint16_t PA7_HZ = 1000; //PA7输出信号频率
uint8_t PA7_D = 10; //PA7输出信号占空比
uint16_t PA1_HZ = 1000; //PA1输出信号频率
uint8_t PA1_D = 10; //PA1输出信号占空比
uint8_t page = 1; //page1:PA1数据页 page2:PA7数据页
uint8_t mode = 1; //当前模式 1:按键控制 0:串口控制
const uint16_t HZ_pace = 1000;
const uint16_t HZ_max = 10000;
const uint16_t HZ_min = 1000;
const uint8_t D_pace = 10;
const uint8_t D_max = 90;
const uint8_t D_min = 10;
/*频率改变*/
void HZ_Change()
{
if(page == 1)//PA1
{
PA1_HZ+=HZ_pace;
if(PA1_HZ > HZ_max)
{
PA1_HZ = HZ_min;
}
}
else if(page == 2)//PA7
{
PA7_HZ+=HZ_pace;
if(PA7_HZ > HZ_max)
{
PA7_HZ = HZ_min;
}
}
PWM_change();//频率、占空比改变
HAL_TIM_Base_Start(&htim6);//开启定时器
}
/*占空比改变*/
void D_Change()
{
if(page == 1)//PA1
{
PA1_D+=D_pace;
if(PA1_D > D_max)
{
PA1_D = D_min;
}
}
else if(page == 2)//PA7
{
PA7_D+=D_pace;
if(PA7_D > D_max)
{
PA7_D = D_min;
}
}
PWM_change();
}
/*模式改变*/
void Mode_Change()
{
mode = !mode;//模式改变
if(mode == 1)//按键模式
{
LED[3] = 0;
}
else//串口模式
{
LED[3] = 1;
}
LED_Control(LED);//LED更新
}
/*数据页改变*/
void Page_Change()
{
if(page == 1)//PA1数据页->PA7数据页
{
page = 2;
sprintf(buf," PA7 ");
LED[1] = 1;
LED[2] = 0;
}
else if(page == 2)//PA7数据页->PA1数据页
{
page = 1;
sprintf(buf," PA1 ");
LED[1] = 0;
LED[2] = 1;
}
LED_Control(LED);//LED更新
LCD_DisplayStringLine(Line2,(u8*)buf);//JLCD更新
}
共有两个函数:
1.LCD_InitShow(),在上电启动后对LCD进行初始化显示操作。
2.LCD_Refresh(),LCD更新显示,数据更新后需要实时进行更新显示。
/*LCD初始化显示函数*/
void LCD_InitShow()
{
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line0,(u8*)" ");
LCD_DisplayStringLine(Line1,(u8*)" ");
LCD_DisplayStringLine(Line2,(u8*)" PA1 ");
LCD_DisplayStringLine(Line3,(u8*)" ");
sprintf(buf," F:%d ",PA1_HZ);
LCD_DisplayStringLine(Line4,(u8*)buf);
LCD_DisplayStringLine(Line5,(u8*)" ");
sprintf(buf," D:%d ",PA1_D);
LCD_DisplayStringLine(Line6,(u8*)buf);
LCD_DisplayStringLine(Line7,(u8*)" ");
LCD_DisplayStringLine(Line8,(u8*)" ");
LCD_DisplayStringLine(Line9,(u8*)" ");
}
/*LCD更新函数 page1:PA1 page2:PA7*/
void LCD_Refresh()
{
if(page == 1)
{
sprintf(buf," F:%d ",PA1_HZ);
LCD_DisplayStringLine(Line4,(u8*)buf);
sprintf(buf," D:%d ",PA1_D);
LCD_DisplayStringLine(Line6,(u8*)buf);
}
else if(page == 2)
{
sprintf(buf," F:%d ",PA7_HZ);
LCD_DisplayStringLine(Line4,(u8*)buf);
sprintf(buf," D:%d ",PA7_D);
LCD_DisplayStringLine(Line6,(u8*)buf);
}
}
直接对TIM2和TIM3的寄存器操作即可
ARR – 寄存器存储的是重装载值
CCRx – 定时器x通道的比较值
要使定时器输出对应频率的信号,重装载值=定时器工作频率/目标频率。
控制该信号的占空比,比较值=重装载值*占空比。
void PWM_change()
{
if(page == 1)//PA1
{
TIM2->ARR = 1000000/PA1_HZ;//改变频率
TIM2->CCR2 = TIM2->ARR*PA1_D/100;//改变占空比
TIM2->CNT = 0;//清空计数值
}
else if(page == 2)
{
TIM3->ARR = 1000000/PA7_HZ;//改变频率
TIM3->CCR2 = TIM3->ARR*PA7_D/100;//改变占空比
TIM3->CNT = 0;//清空计数值
}
}
每次串口接收到数据都重新开启定时器,这样能使最后一字节数据接收完5ms后才开始对接收数据进行处理,而不是每接收一个字节数据都去处理一次
/*相关变量*/
uint8_t rec_flag = 0; //串口接收标志位
uint16_t rec_num = 0; //串口一次接收字节数
/*定时器回调函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
...
if(htim == &htim7)
{
HAL_TIM_Base_Stop_IT(&htim7);//关闭定时器7
rec_flag = 1;//接收检测标志位置1
}
...
}
/*串口接收回调函数*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
rec_num++;//接收字节数增加
HAL_UART_Receive_IT(&huart1,&rec_byte,1);//再次打开串口接收中断
TIM7->CNT = 0;//定时器7计数值清零 重新计时
HAL_TIM_Base_Start_IT(&htim7);//开始计时
}
注意调用PWM的start函数打开PWM、以中断方式打开定时器以及打开串口接收中断等
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM6_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM7_Init();
/* USER CODE BEGIN 2 */
LCD_Init();//LCD初始化
LCD_InitShow();//LCD初始化显示
LED_Control(LED);//LED初始化
HAL_UART_Receive_IT(&huart1,&rec_byte,1);//打开串口接收中断
HAL_TIM_Base_Start_IT(&htim6);//开启定时器6
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);//PWM启动
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//PWM启动
printf("uart test...\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
KEY_Process();//按键处理
LCD_Refresh();//LCD更新
if(rec_flag == 1)//串口数据接收标志位
{
rec_flag = 0;//标志位清零
Check_UartRec();//串口数据处理
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
上电默认值F为1000 D为10

上电默认值F为1000 D为10

默认D值为10,占空比为10%,F为1000,输出频率为1KHz

1.按键控制模式:
2.串口控制模式,数据长度不符:
3.切换到PA7数据页,操作成功:

1.蓝桥杯嵌入式赛前梳理
2.一文看懂如何使用RTC秒中断
3.一文看懂如何解决LED与LCD冲突
4.一文看懂如何玩转显示高亮

以上就是全部内容,如有错误请批评指正。
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
目录前言: 一、ASC分析代码实现二、 卡片分析代码实现三、 直线分析代码实现四、货物摆放分析代码实现小结:前言: 在刷题的过程中,发现蓝桥杯的题目和力扣的差别很大。让人有一种不一样的感觉,蓝桥杯题目偏向对于实际问题用编程去的解决,而力扣给人感觉很锻炼自己的编程思维,逻辑能力。两者结合去刷,相信会有不一样的收获。 一、ASC 已知大写字母A的ASCII码为65,请问大写字母L的ASCII码是多少?分析 这道题目看上去很简单,我们需确定自己计算的准确,所以我建议用编程去解决。代码实现publicclassTest8{publicstaticvoidmain(String[]args){Sy
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
?作者主页:静Yu?简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者?社区地址:前端知识交流社区?博主的个人博客:静Yu的个人博客?博主的个人笔记本:前端面试题个人笔记本只记录前端领域的面试题目,项目总结,面试技巧等等。接下来会更新蓝桥杯官方系统基础练习的VIP试题,依然包括解题思路,源代码等等。问题描述:给定当前的时间,请用英文的读法将它读出来。时间用时h和分m表示,在英文的读法中,读一个时间的方法是: 如果m为0,则将时读出来,然后加上“o’clock”,如3:00读作“threeo’clock”。 如果m不为0,则将时读出来,然后将分读出来,如5
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N
在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:
我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed
我在Windows上运行ruby1.9.2并试图移植在Ruby1.8中工作的代码。该代码使用以前运行良好的Open4.popen4。对于1.9.2,我做了以下事情:通过geminstallPOpen4安装了POpen4需要POpen4通过require'popen4'尝试像这样使用POpen4:Open4.popen4("cmd"){|io_in,io_out,io_er|...}当我这样做时,我得到了错误:nosuchfiletoload--win32/open3如果我尝试安装win32-open3(geminstallwin32-open3),我会收到错误消息:win32-op
DellInspiron5488加内存32G 原装内置内存仅仅8G,目前看,真的太小了! 1.内存型号Dell5488内存型号:DDR42666。笔记本有两个内存插槽,原装占了一个,还能扩展一个。 2.买内存如果买Dell原装笔记本内存,8G就得500块左右。 我咨询了一下,三星的笔记本内存,可以兼容。16G,299块(2023年2月23日,京东价) Dell5488内存组合,最多只能插两根16G内存。 我于是买了两根三星16G内存。装上,很爽😄 跑国产系统统信UOS,再也看不到用交换区了,32G内存,爽!