蓝桥杯嵌入式快速入门
蓝桥杯嵌入式快速入门
介绍
蓝桥杯嵌入式使用的单片机是STM32G431RBT6,内核ARM Cortex - M4,MCU+FPU,170MHz/213DMIPS,高达128KB Flash,32KB SRAM,其余的外设就不多介绍了,参照数据芯片数据手册
CT117E-M4开发板资源:微控制器STM32G431RBT6、一路USB转串口、2.4寸TFT-LCD、4个功能按键、1个复位按键、8个LED、一个E2PROM(AT24C02)、一个可编程电阻(100K)、2路信号发生器、2个分压电位器、2个扩展接口、一个CMSIS DAP Link调试器
前期准备
①安装串口驱动(通过设备管理器),若为windows10则不需手动安装
②在cubemx中安装hal库
③在keil中安装器件包
第一个程序
①cubemx中选择芯片型号
②使能必要IO口:RCC_OSC_IN and RCC_OSC_OUT(External crystal oscillator)、SWDIO and SWCLK(CMSIS DAP Link)
③配置时钟Clock Configuration。外部时钟设置为24MHz,第一个选择器选择HSI即内部RC振荡器(没用HSE是因为引脚与LED冲突),PLLM为2分频,PLL内部先乘20再除以2,最终得80MHz,第二个选择器选择PLLCLK,后APB1和APB2总线时钟均设置为80MHz(此设置根据官方学习程序配置)
④在Project Manager中,确定工程名称、位置、IDE,勾选为每个外设初始化生成c和h文件。GENERATE CODE生成工程
⑤在keil中,打开Options for Target(魔术棒),Output勾选Create HEX File,Debug菜单右上角选择CMSIS-DAP Debugger,进入Setting,Port选择SW,Max Clock选择10MHz,如果插上开发板(注意板子有两个接口,插上DOWNLOAD接口),在SW Device中可以看到芯片IDCODE和Name,进入Flash Download选择Erase Full Chip,Reset and Run,然后下方Add添加Flash编程算法,选择STM32G4X,128K,确定保存
⑥编译,下载,可以看到程序下载成功,但是LED灯不稳定,原因是SN74HC573ADWR芯片引脚电平不稳定导致,可以不用管
LED
创建新工程,LED灯与MCU之间使用SN74HC573ADWR芯片连接,使能PD2(信号锁存引脚,点亮灯的操作需要先对灯操作,然后依次拉高、拉低PD2引脚)拉低,使能PC8-PC15对应LED1-LED8,低电平亮,高电平灭
代码如下:
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); //拉高PD2,将PC信号送入输入端HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);//拉低PD2,锁存输出端信号HAL_Delay(1000);
注:操作LED时需要设置全部的LED状态,因为对LCD操作也会影响LED状态
按键和定时器中断
为什么按键和定时器中断要一起讲呢?因为传统按键检测有两种方式,一种直接读IO电平状态,另一种是中断,这两种都不太好处理按键抖动,因此使用定时器来计数判断按键是否按下,经过测试效果还行
创建新工程,使用tim1,时钟源选择Internal Clock,分频系数选择80,意味着一个tick是1us,计数值设为9999,则定时器中断周期为10ms,在NVIC Settings中使能更新中断
代码中需要在主循环上方手动启动定时器中断:
HAL_TIM_Base_Start_IT(&htim1);
在tim.c文件最后加上回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if (htim == (&htim1)){static uint8_t key1count = 0; //按键计数if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){key1count ++;}else key1count = 0;if(key1count == 8){ //这个值根据情况设定,该if内为key1按下执行的内容HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); key1count = 0; //计数清零a++;} }
}// 长、短按
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if (htim == (&htim1)){static int key1count = 0,key11count = 0; //按键计数 key1count是判断有按键按下,key11count是判断长或短按if(key1count >= 8){ //这个值根据情况设定 消抖 key11count++;if(key11count>=100){ //长按HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); }else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET){ //短按 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); }} if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){key1count ++;}else {key1count = 0;key11count=0;} }
}
其实直接读取IO电平状态判断按键是否按下也是可行的:
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){HAL_Delay(100);if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14 | GPIO_PIN_15);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}
}
串口重定义、发送和接收中断
CT117E-M4的DOWNLOAD接口默认与USART1即PA9、PA10连接,因此这个接口可以用于调试
cubemx中使能USART1为Asynchronous即异步通信,使能PA9和PA10为串口功能,其余串口通信参数可以自行设定
重定向:
#include <stdio.h>
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1 , 0xffff);return ch;
}
串口中断仍以USART1为例,只需在cubemx中勾选NVIC Settings允许中断即可
需要在主循环上方开启中断接收:
HAL_UART_Receive_IT(&huart1, &RES, 1);
在usart.c中调用中断回调函数并编写用户代码:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart == (&huart1)){if(RES == 'A'){HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); } else{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); }HAL_UART_Receive_IT(&huart1, &RES, 1);}
}
LCD
比赛时会提供资源数据包,在其中有lcd.h、lcd.c、font.h三个文件,采用IO口模拟通信方式,根据原理图初始化所有的IO口为推挽输出形式,其余配置均不变,然后将上述三个文件添加到工程中
使用时直接调用lcd.h中函数即可:
LCD_Init();
LCD_Clear(White); //清屏,并将背景设置为白色LCD_SetBackColor(Blue); // 设置即将显示的文字背景颜色
LCD_SetTextColor(White); // 设置即将显示的文字的颜色
// void LCD_DisplayStringLine(u8 Line, u8 *ptr)
LCD_DisplayStringLine(Line0, (uint8_t *)" "); // 显示字符串
LCD_DisplayStringLine(Line1, (uint8_t *)" ");
LCD_DisplayStringLine(Line2, (uint8_t *)" LCD Test ");
LCD_DisplayStringLine(Line3, (uint8_t *)" ");
LCD_DisplayStringLine(Line4, (uint8_t *)" ");// 显示浮点数 num为35.2 0x30为'0'的ascii码
LCD_SetTextColor(Red);
LCD_DisplayChar(Line0,320,(int)num/10+0x30);
LCD_SetTextColor(Red);
LCD_DisplayChar(Line0,304,(int)num%10+0x30);
LCD_SetTextColor(Red);
LCD_DisplayChar(Line0,288,0x2E); // 0x2E为 '.'的ascii码
LCD_SetTextColor(Red);
LCD_DisplayChar(Line0,272,((int)(num*10))%10+0x30);
// 另一种显示浮点数方式
char buf[20];
LCD_SetBackColor(Blue);
LCD_SetTextColor(Red);
sprintf(buf, " VAL:%.2fV", getADC()*3.3/4096);
HAL_Delay(100);
LCD_DisplayStringLine(Line8, (uint8_t *)buf);
注:LCD为320*240,一共10行,Line0-Line9,每行可以显示20个字符,即每个字符320/20=16,最左侧为320,最右侧为1
ADC、DAC
蓝桥杯板子上有两路ADC采样电路,R37对应PB15,R38对应PB12
以PB15为例,初始化为ADC2_IN15,勾选左侧IN15 Single-ended,时钟分频器选择异步时钟1分频,如果1分频不行选择2分频,总之选择异步时钟,12bit,右对齐,其余不变
uint32_t adcValue = 0;char adcArray[20];HAL_ADC_Start(&hadc2); // 每次读值都要先手动启动
ADCadcValue = HAL_ADC_GetValue(&hadc2); // 读值
sprintf(adcArray," VAL:%.2fV",adcValue*3.3/4096); // 转换
LCD_SetTextColor(Red); // 设置文字颜色//
HAL_Delay(100);
LCD_DisplayStringLine(Line8, (uint8_t *)adcArray); // 显示
R38同理
DAC以PA4为例,它在板子的J3扩展口上
使能PA4的DAC1_OUT1功能,OUT1_mode设置为Connected to external pin only,其余参数不变
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1); // 以下可以封装成一个函数
vol = 2.5; // 输出2.5V
temp = (4096*vol/3.3);
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);
PWM和输入捕获
板子上有两个定时器输入输出口,PA15对应R40、J10跳线帽,PB4对应R39、J9跳线帽
输入捕获时,是捕获信号发生器生成的方波频率,以PA15为例,使能其为定时器二通道一功能,Input Capture direct mode,使能定时器二全局中断,其余不变直接生成
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 启动定时器输入捕获模式
uint32_t cc1_value_2 = 0; // TIMx_CCR1 的值
uint32_t f40 = 0;// 中断服务函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ cc1_value_2 = __HAL_TIM_GET_COUNTER(&htim2); __HAL_TIM_SetCounter(&htim2,0); f40 = 1000000/cc1_value_2; HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
}
// 显示频率
sprintf(buf, " FRQ(R40):%dHz ",f40);
LCD_DisplayStringLine(Line8, (uint8_t *)buf);
PWM输出时需要将跳线帽拔下
cubemx中选择定时器时钟源为内部时钟,通道一设置为PWM Generation CH1,然后设置分频系数、计数模式、计数周期值(ARR)、使能自重装载预装载、PWM模式、脉宽(Duty)、极性
HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel); // 开启PWM输出使用函数或者寄存器操作即可修改占空比或者频率
EE
板子上有一个M24C02的EEPROM,容量为2048bit,2Kbit,8×256,即256Byte
使用模拟IIC驱动,时钟线为PB6,数据线为PB7
cubemx初始化引脚为输出,然后进入keil,将i2c.c和i2c.h文件移植到工程中,添加入工程中
I2CInit(); // 初始化I2C,其实这句不需要,因为cube已经帮我们初始化了引脚
// 编写读写函数
// 24c02读函数
uint8_t x24c02_read(uint8_t address){ unsigned char val;I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(address); I2CWaitAck(); I2CStart(); I2CSendByte(0xa1); I2CWaitAck(); val = I2CReceiveByte(); I2CWaitAck(); I2CStop(); return(val);
}
// 24c02写函数
void x24c02_write(unsigned char address,unsigned char info){ I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(address); I2CWaitAck(); I2CSendByte(info); I2CWaitAck(); I2CStop();
}
// 然后调用即可
val = x24c02_read(0);
x24c02_write(0, ++val);
RES
可编程电阻(变阻器),存储器类型为RAM
采用模拟I2C,PB6为SCL,PB7为SDA
I2CInit(); // 初始化I2C,其实这句不需要,因为cube已经帮我们初始化了引脚
// 编写读写函数
// 写电阻,设置电阻值
void write_resistor(uint8_t value){ I2CStart(); I2CSendByte(0x5E); I2CWaitAck(); I2CSendByte(value); I2CWaitAck(); I2CStop();
}
// 读电阻,读取电阻值
uint8_t read_resistor(void){ uint8_t value; I2CStart(); I2CSendByte(0x5F); I2CWaitAck(); value = I2CReceiveByte(); I2CSendNotAck(); I2CStop(); return value;
}
// 打印实际电阻值
LCD_SetTextColor(Red);
sprintf(buf, " RES VAL:%.1fK ", (0.78740*read_resistor()));
LCD_DisplayStringLine(Line8, (uint8_t *)(buf));
附2022年十三届蓝桥杯嵌入式省赛代码:https://pan.baidu.com/s/1SnbMTCun6-MkDPDCdr8-yw
提取码:3h0s
(题主比赛时花费两小时完成,有些地方如密码验证并未想的很周到,其余功能均已完成,供大家学习使用)
蓝桥杯嵌入式快速入门相关推荐
- 蓝桥杯Python快速入门(4)
目录 01.字符串 [字符串格式化] [字符串常用方法] 1.去掉空格和特殊符号 2.字符串的搜索和替换 3.字符串的测试和替换函数 4.字符串的分割 5.连接字符串 6.截取字符串(切片) 7.求值 ...
- stm32入门学什么板子_“蓝桥杯”嵌入式stm32开发入门(1)概述
声明:笔者绝不是给"蓝桥杯"打广告,而是笔者曾经参加过蓝桥杯嵌入式设计与开发比赛,想借此机会总结并分享自己的学习中的点点滴滴. 此系列教程将以蓝桥杯官方指定的开发板和接口板来深入浅 ...
- 【蓝桥杯嵌入式】比赛笔记(2)根据固件库快速配置各模块初始化
[蓝桥杯嵌入式]比赛笔记(2)根据固件库快速配置各模块初始化 因为蓝桥杯比赛时间很短,并且如果自己去记忆各模块初始化的话,也难免有问题,所以这里给出一个通过固件库的快速初始化模块的方法. 比赛提供固件 ...
- 蓝桥杯嵌入式第一篇 点亮LED灯开启成功之路
文章目录 前言 一.准备工作 1.拿到开发板第一步看原理图 2.下载STM32cubeMX 二.开始点灯 1.查看LED原理图 2.cubeMX配置 3.代码实现 总结 前言 从这篇文章开始将为大家带 ...
- 第九届蓝桥杯-嵌入式比赛体会与备赛经验
原文地址:http://www.cnblogs.com/NickQ/p/8721317.html 说起蓝桥杯,相信很多电子类的学生,应该很熟悉了吧...上周日,我也去湖北工业大学参与了一下.说起这次经 ...
- 蓝桥杯嵌入式CT117E硬件开发平台经验分享11 | 第九届蓝桥杯国赛题
基于 基于 CT117E 嵌入式竞赛板 嵌入式竞赛板 的 "电子秤"程序设计与调试 赛题硬件框图 由于赛题细节多,赛题PDF要求书放入了附件,链接后续加入.本文主要讲述本届题目的困 ...
- 蓝桥杯嵌入式STM32 G431 HAL库开发速成指南(1)LED
本教程适用于报名参加蓝桥杯嵌入式用新开发板(G431)且想要快速开发的小白,不具体讲解复杂的原理,只讲Cubemx初始化配置以及在KEIL里面使用相应的库函数功能对外设进行编程. CUBEMX配置流程 ...
- 【蓝桥杯嵌入式】应赛技巧①多屏切换
摘要 本文章基于国信长天CT1117E-M4开发板,讲述了在蓝桥杯嵌入式比赛过程中双屏切换的实现技巧,帮助同学们在比赛中快速实现该功能. 命题趋势分析 统计分析近5年的省赛真题,都出现了通过按键切换屏 ...
- 【STM32G431RBTx】备战蓝桥杯嵌入式→扩展模块→SEG
文章目录 前言 一.软件准备 二.SEG 1.扩展板上模块的原理图以及我们需要配置的元素 2.CubeMx的配置步骤 三.测试代码 四.演示效果 五.工程链接 六.总结 前言 初赛结束之后就应该火速准 ...
- 【STM32G431RBTx】备战蓝桥杯嵌入式→基本模块→LED
文章目录 前言 一.软件准备 二.LED 1.G431RETx的原理图以及我们需要配置的元素 2.CubeMx的配置步骤 3.别忘了设置调试接口为SW 4.生成工程 5.测试代码 三.效果展示 总结 ...
最新文章
- 谋定菲律宾农业全产业链建设 对话国际农民丰收节贸易会
- C++笔记——指针数组/数组指针
- python爬虫第一课 开发环境配置
- 【渝粤题库】陕西师范大学163201 旅游科学引论作业(专升本)
- java 集合modcount_源码|jdk源码之LinkedList与modCount字段
- .h 与 .hpp 文件
- bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)
- Hi,我是易建科技eKing Cloud!
- c语言面试题-基本概念
- 松下伺服电机a6测试软件,松下A6伺服选型步骤
- 锐捷计算机教室排顺序,大学四年说话最多的一堂课是在锐捷智慧教室
- Python数据分析通关,30个案例!
- SDN亟需一个WinTel联盟
- LaTeX插入参考文献,简单高效
- 迷宫游戏|自动寻径|随机生成迷宫地图|UI|闯关|地图反转
- oracle修改sql域名,oracle更改数据库权限
- 实参可以是任意类型吗_5本可以解决书荒的粮草小说,类型随机,看看有你喜欢的吗?...
- PowerVR SGX
- Springboot项目启动异常 org.springframework.beans.factory.UnsatisfiedDependencyException
- 贝恩分类法(行业集中度)