蓝桥杯嵌入式快速入门

介绍

​ 蓝桥杯嵌入式使用的单片机是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
(题主比赛时花费两小时完成,有些地方如密码验证并未想的很周到,其余功能均已完成,供大家学习使用)

蓝桥杯嵌入式快速入门相关推荐

  1. 蓝桥杯Python快速入门(4)

    目录 01.字符串 [字符串格式化] [字符串常用方法] 1.去掉空格和特殊符号 2.字符串的搜索和替换 3.字符串的测试和替换函数 4.字符串的分割 5.连接字符串 6.截取字符串(切片) 7.求值 ...

  2. stm32入门学什么板子_“蓝桥杯”嵌入式stm32开发入门(1)概述

    声明:笔者绝不是给"蓝桥杯"打广告,而是笔者曾经参加过蓝桥杯嵌入式设计与开发比赛,想借此机会总结并分享自己的学习中的点点滴滴. 此系列教程将以蓝桥杯官方指定的开发板和接口板来深入浅 ...

  3. 【蓝桥杯嵌入式】比赛笔记(2)根据固件库快速配置各模块初始化

    [蓝桥杯嵌入式]比赛笔记(2)根据固件库快速配置各模块初始化 因为蓝桥杯比赛时间很短,并且如果自己去记忆各模块初始化的话,也难免有问题,所以这里给出一个通过固件库的快速初始化模块的方法. 比赛提供固件 ...

  4. 蓝桥杯嵌入式第一篇 点亮LED灯开启成功之路

    文章目录 前言 一.准备工作 1.拿到开发板第一步看原理图 2.下载STM32cubeMX 二.开始点灯 1.查看LED原理图 2.cubeMX配置 3.代码实现 总结 前言 从这篇文章开始将为大家带 ...

  5. 第九届蓝桥杯-嵌入式比赛体会与备赛经验

    原文地址:http://www.cnblogs.com/NickQ/p/8721317.html 说起蓝桥杯,相信很多电子类的学生,应该很熟悉了吧...上周日,我也去湖北工业大学参与了一下.说起这次经 ...

  6. 蓝桥杯嵌入式CT117E硬件开发平台经验分享11 | 第九届蓝桥杯国赛题

    基于 基于 CT117E 嵌入式竞赛板 嵌入式竞赛板 的 "电子秤"程序设计与调试 赛题硬件框图 由于赛题细节多,赛题PDF要求书放入了附件,链接后续加入.本文主要讲述本届题目的困 ...

  7. 蓝桥杯嵌入式STM32 G431 HAL库开发速成指南(1)LED

    本教程适用于报名参加蓝桥杯嵌入式用新开发板(G431)且想要快速开发的小白,不具体讲解复杂的原理,只讲Cubemx初始化配置以及在KEIL里面使用相应的库函数功能对外设进行编程. CUBEMX配置流程 ...

  8. 【蓝桥杯嵌入式】应赛技巧①多屏切换

    摘要 本文章基于国信长天CT1117E-M4开发板,讲述了在蓝桥杯嵌入式比赛过程中双屏切换的实现技巧,帮助同学们在比赛中快速实现该功能. 命题趋势分析 统计分析近5年的省赛真题,都出现了通过按键切换屏 ...

  9. 【STM32G431RBTx】备战蓝桥杯嵌入式→扩展模块→SEG

    文章目录 前言 一.软件准备 二.SEG 1.扩展板上模块的原理图以及我们需要配置的元素 2.CubeMx的配置步骤 三.测试代码 四.演示效果 五.工程链接 六.总结 前言 初赛结束之后就应该火速准 ...

  10. 【STM32G431RBTx】备战蓝桥杯嵌入式→基本模块→LED

    文章目录 前言 一.软件准备 二.LED 1.G431RETx的原理图以及我们需要配置的元素 2.CubeMx的配置步骤 3.别忘了设置调试接口为SW 4.生成工程 5.测试代码 三.效果展示 总结 ...

最新文章

  1. 谋定菲律宾农业全产业链建设 对话国际农民丰收节贸易会
  2. C++笔记——指针数组/数组指针
  3. python爬虫第一课 开发环境配置
  4. 【渝粤题库】陕西师范大学163201 旅游科学引论作业(专升本)
  5. java 集合modcount_源码|jdk源码之LinkedList与modCount字段
  6. .h 与 .hpp 文件
  7. bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)
  8. Hi,我是易建科技eKing Cloud!
  9. c语言面试题-基本概念
  10. 松下伺服电机a6测试软件,松下A6伺服选型步骤
  11. 锐捷计算机教室排顺序,大学四年说话最多的一堂课是在锐捷智慧教室
  12. Python数据分析通关,30个案例!
  13. SDN亟需一个WinTel联盟
  14. LaTeX插入参考文献,简单高效
  15. 迷宫游戏|自动寻径|随机生成迷宫地图|UI|闯关|地图反转
  16. oracle修改sql域名,oracle更改数据库权限
  17. 实参可以是任意类型吗_5本可以解决书荒的粮草小说,类型随机,看看有你喜欢的吗?...
  18. PowerVR SGX
  19. Springboot项目启动异常 org.springframework.beans.factory.UnsatisfiedDependencyException
  20. 贝恩分类法(行业集中度)

热门文章

  1. 任正非的《北国之春》
  2. 推荐一款鼠标手势的软件,开源且免费
  3. java咖啡馆_Java咖啡馆(11):Java插件技术
  4. 数字滤波器 matlab 仿真,基于matlab的数字滤波器的设计及仿真ppt课件
  5. WPF 设置本地打印的纸张和方向
  6. GATK GATK best practices notes
  7. MySQL数素数_素数个数-欧拉筛法
  8. 牛客练习赛41:球的体积并【球缺】
  9. Photoshop 更改图片颜色
  10. 中国移动科普:为什么手机移动网络要叫 “蜂窝移动网络”