当前位置: 首页 > news >正文

电子信息工程专业打工人的蓝桥杯嵌入式竞赛时记

文章目录

  • 前言
  • 一、基础入门
    • 1.GPIO
      • GPIO的引脚速度
      • GPIO的翻转速度
      • 引脚功能:端口复用和端口重映射
      • 输入输出模式
      • 引脚设置
    • 2.新建工程(F103+G431)
    • 3.必备宏定义(F103)
    • 4.注意库函数(F103)
    • 5.时钟系统及滴答定时器
    • 6.中断
    • 7.其他编程注意事项
  • 二、开发学习
    • 标准库版本
      • 1.LED
        • LED与LCD冲突解决方法
      • 2.蜂鸣器
      • 3.独立按键
      • 4.LCD
        • LCD字符高亮颜色显示
      • 5.TIMER
      • 6.实时时钟
      • 7.USART
      • 8.24C02
      • 9.ADC
      • 10.PWM & TIM_OC
      • 11.TIM_IC
      • 12.DMA
      • 13.数码管
      • 14.ADC按键
      • 15.DS18B20
      • 16.光敏电阻
      • 17.ADCx2双通道
      • 18.DTH11
      • 19.TLC551测量
      • 20.LIS302DL
      • 蓝桥杯嵌入式旧板资料包免费下载
      • 蓝桥杯嵌入式旧板程序代码免费下载
    • ************************************************
    • HAL库版本
      • 定时器
      • 串口
      • 输入捕获
      • ADC
      • RTC

前言

蓝桥杯嵌入式的学习总结,本文主要针对蓝桥杯嵌入式作出总结(STM32F103RBT6型号标准库版本+STM32G431RBT6型号HAL库版本)进行讲解,由于第一年已用标准库参赛,第二年HAL库版仅为学习链接,可在文章旧版讲解的基础上对新版进行学习。如果读者时间充足,建议先学好模电数电基础知识,同时用开发板实际操作,能让学习事半功倍且能学习更深入。

一、基础入门

1.GPIO

首先GPIO最基本、最简单的作用是我们可以通过编程的方式让它作输入或者输出,而输入/输出的形式为高低电平(通常0V为低电平,3.3V为高电平)。 要让GPIO作输入或者输出,首先就需要对IO口相关的寄存器进行配置。而寄存器是中央处理器内的组成部分,寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。因此对IO口的初始化就是向相关寄存器里面写不同的值,从而确定使用哪一个IO口(IO口标号)、以及IO口工作模式(输入还是输出)、输出速度等参数。在经过初始化之后就可以正常使用IO口了,比如如果IO口设置成了某个输入模式,就可以通过调用相关函数或者直接操作相关寄存器去得到IO口的电平是高电平还是低电平。
—>单片机引脚与端口,引脚和GPIO的区别

GPIO的引脚速度

输出驱动电路响应速度,芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制降低功耗的目的。可理解为: 输出驱动电路的带宽,即一个驱动电路可以不失真地通过信号的最大频率。如果一个信号的频率超过了驱动电路的响应速度,就有可能信号失真。GPIO的引脚速度跟应用相匹配,速度配置越高,噪声越大,功耗越大。
GPIO的引脚速度跟应用匹配(推荐10倍以上)。
USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小。
I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度。
SPI接口,若使用18M或9M波特率,需要选用50M的GPIO的引脚速度。

GPIO的翻转速度

GPIO的翻转速度指输入/输出寄存器的0,1值反映到外部引脚(APB2上)高低电平的速度。手册上指出GPIO最大翻转速度可达18MHz。
通过简单的程序测试,用示波器观察到的翻转时间: 是综合的时间,包括取指令的时间、指令执行的时间、指令执行后信号传递到寄存器的时间(这其中可能经过很多环节,比如AHB、APB、总线仲裁等),最后才是信号从寄存器传输到引脚所经历的时间。

引脚功能:端口复用和端口重映射

复用就是当这个GPIO作为片内外设功能引脚;一个引脚可用作实现多个功能,原理图上的引脚注释为可复用功能(或芯片数据手册可查),1.做普通IO输入输出,2.其他外设的输入输出;好处是节省外设与GPIO所用引脚数量;STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。
重映射就是将所需的片内外设复用功能从原本默认IO口重新定义到其他可实现该功能的引脚,芯片内部已经固定了只能映射到固定的地方,分部分重映射(端口有一个默认复用功能和多个可重映射功能)和完全重映射(端口有一个或多个默认复用功能和一个可重映射功能),stm32中文手册可查(通过配置该复用功能重映射哪个端口);好处是防止该复用功能默认引脚被占用,多个功能所需引脚冲突;
复用功能I/O(AFIO):在使用引脚的单个复用功能时无需打开AFIO时钟,只需使能该复用功能的时钟和需要的输入输出模式;复用功能重映射时需使能AFIO时钟。
—>端口复用和端口重映射
—>片上外设和片外外设的区别
—>什么时候需要复用IO(AFIO)

输入输出模式

驱动能力:就是指输出电流的能力。对于驱动大负载(即负载内阻越小,负载越大)时,例如IO输出为5V,驱动的负载内阻为10ohm,于是根据欧姆定律可以正常情况下负载上的电流为0.5A(推算出功率为2.5W)。显然一般的IO不可能有这么大的驱动能力,也就是没有办法输出这么大的电流。于是造成的结果就是输出电压会被拉下来,达不到标称的5V。当然如果只是数字信号的传递,下一级的输入阻抗理论上最好是高阻,也就是只需要传电压,基本没有电流,也就没有功率,于是就不需要很大的驱动能力。
FT:容忍5V输入
浮空输入(GPIO_Mode_IN_FLOATING):电平会完全取决于外部电路而与内部电路无关,无外部电路接入时,IO脚浮空会使得电平不确定,由输入数据寄存器(只读)读取。
上拉输入(GPIO_Mode_IPU):无外部电路接入时,IO脚上拉使电平始终为高电平,读取外部电路低电平明显,无法判断高电平的输入,由输入数据寄存器(只读)读取。
下拉输入(GPIO_Mode_IPD):无外部电路接入时,IO脚上拉使电平始终为低电平,读取外部电路高电平明显,无法判断低电平的输入,由输入数据寄存器(只读)读取。
模拟输入(GPIO_Mode_AIN):不经过施密特触发器,将外部信号直接传输到数模转换通道上,片上外设(ADC)直接读取IO脚输入。
推挽输出(GPIO_Mode_Out_PP):上PMOS下NMOS,降低功耗带载能力强,跳变速度快,但无法完成“线与”功能,由输出数据寄存器(可读可写)读取位寄存器后输出给IO脚。
复用推挽输出(GPIO_Mode_AF_PP):片上外设功能的推挽输出。
开漏输出(GPIO_Mode_Out_OD):可以根据外部电路需要多少V的高电平来接入外部上拉电压,实现线与的功能,IIC一个低电平,可以拉低整个总线。
复用开漏输出(GPIO_Mode_AF_OD):片上外设功能的开漏输出
GPIOx_IDR是端口的输入数据寄存器,GPIOx_ODR是端口的输出寄存器

—>深刻理解stm32输入输出模式
—>施密特触发器详解

引脚设置

寄存器赋值输入可以使用“|”操作,但读取和定时器通道只能单个位进行操作。
—>位带操作
—>寄存器编程

2.新建工程(F103+G431)

赛点资源数据包 -> 8-液晶驱动参考例程 -> (复制)CT117E-LCD文件夹 -> (粘贴)考生文件夹
好处:大大节省建立工程的时间,不用专门考虑工程格式,不用担心建立工程时的小细节浪费比赛时间,方便练习。
工程文件改名:粘贴后清空子文件夹Output内全部内容 -> 子文件夹Project内除后缀《.uvproj工程和.uvopt文件》其他文件全部删除 -> 剩下两个文件分别命名后进入工程为.axf 文件改名。(.uvproj工程文件为工程开辟空间,是工程核心;.uvopt文件为工程保存工程配置,关联各文件内容,缺少.uvopt文件MDK缺失结构体变量提示功能,非工程链接;uvopt和uvproj都是keil工程文件,共同说明这你工程里有哪些文件,文件有没有被编译过,工程目录树是怎么组织的等等信息)
.axf 文件改名:工程中Options for Target(魔术棒)-> Output -> Name of Executable -> 指定文件命名后编译 -> 考生文件夹Output子文件夹 -> 找到.axf后打包提交
注:该方法只适用于蓝桥杯嵌入式旧版比赛

3.必备宏定义(F103)

工程中Configure target options -> C/C++ -> Define选项STM32F10x_MD宏定义作用为使system_stm32f10x.c文件执行设置默认系统时钟72MHz。
startup_stm32f10x_cl.s(启动文件) → SystemInit() → SetSysClock () → SetSysClockTo72(),其中所有函数在system_stm32f10x.c文件。


工程中Configure target options -> C/C++ -> Define选项USE_STDPERIPH_DRIVER宏定义作用为使stm32f10x.h文件执行包含所有外设头文件。
stm32f10x.h(通用头文件) → #include “stm32f10x_conf.h” → 包含所有外设头文件。

—>#预编译详解

4.注意库函数(F103)

voidRCC_APB2PeriphClockCmd(uint32_tRCC_APB2Periph,FunctionalState NewState);/*外设时钟使能*/voidRCC_APB2PeriphResetCmd(uint32_tRCC_APB2Periph,FunctionalState NewState);/*复位所有IO口*/voidGPIO_Write(GPIO_TypeDef*GPIOx,uint16_tPortVal);/*对GPIOx_ODR写入,系列IO设置*/voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);/*对GPIOx_BSRR写入,单位置1*/voidGPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);/*对GPIOx_BRR写入,单位置0*/voidTIM_OCxPreloadConfig(TIM_TypeDef*TIMx,uint16_tTIM_OCPreload);/*输出比较模式更改比较值后在下次更新事件生效或立即生效*/voidTIM_OCxPolarityConfig(TIM_TypeDef*TIMx,uint16_tTIM_OCPolarity);/*设置输入捕获极性,上升沿或下降沿*//*TIM_OCxPolarityConfig()函数用作输入捕获极性配置时(keil不可跳转到该宏定义),uint16_t TIM_OCPolarity参数可取以下值*/#defineTIM_ICPolarity_Rising((uint16_t)0x0000)#defineTIM_ICPolarity_Falling((uint16_t)0x0002)/*TIM_OCxPolarityConfig()函数用作输出极性配置时(默认),uint16_t TIM_OCPolarity参数可取以下值*/#defineTIM_OCPolarity_High((uint16_t)0x0000)#defineTIM_OCPolarity_Low((uint16_t)0x0002)

5.时钟系统及滴答定时器

/** *1Mhz的频率,每秒钟可以执行1.25M指令。嵌入式stm32默认上电系统时钟8M,每个指令的执行周期为1s/8*1.25M=0.1us */

—>stm32的指令周期
—>时钟系统
uint32_t SysTick_Config(uint32_t ticks)函数在core_cm3.h头文件定义,void SysTick_Handler(void)中断函数在stm32f10x it.c源文件定义。
—>SysTick(滴答定时器)

6.中断

—>stm32中断优先级的使用及注意事项

7.其他编程注意事项

1、判断语句条件中==优先级大于&、|、^、&&、||;加减乘除优先级大于移位运算
2、整型常量(数值)默认设置为int类型,char和short类型与整型常量运算过程中以int类型为范围;常数后加“.”或“.0”表示该常数为double型。
unsigned int类型:0 ~ (2^32 - 1 —> 4294967295);
—>数值范围注意事项
float类型:小数点后有效数字6~7位;
double类型:小数点后有效数字15~16位;
3、浮点数注意事项:
常数后缀:
U:unsigned
L:long / double
F:float
float数据类型赋值运算时常数后需加F

4、—>计算机负数计算
5、—>keil中code和const的区别
6、—>主机字节序
7、—>STM32堆栈区
8、—>字节和字长区别
9、程序中数组绝对不能溢出
10、函数中的局部变量存储在栈中,栈空间大小1~2KB,一个函数(包括main函数)一次性不能设置太大的数组,大数组设置为全局变量(静态存储区)
10、—>寄存器,锁存器,触发器,存储器的区别
11、—>浅论各种调试接口
12、—>C语言中的volatile关键字

二、开发学习

标准库版本

1.LED

上电默认输出低电平;与锁存器相连,使能端(PD2)高电平有效;引脚为PC8~15,APB2总线控制时钟,推挽输出控制亮灭。
锁存器的作用(蓝桥杯嵌入式中至与LED功能相连)
锁存器(Latch)是一种对 脉冲电平敏感的 存储单元 电路,它们可以在特定输入脉冲电平作用下改变状态。锁存,就是把信号暂存以维持某种电平状态。锁存器的最主要作用是缓存,其次完成高速的控制器与慢速的外设的不同步问题,再其次是解决驱动的问题,最后是解决一个 I/O 口既能输出也能输入的问题。锁存器是利用电平控制数据的输入,它包括不带使能控制的锁存器和带使能控制的锁存器。
控制LED亮灭:先配置相应I/O口,再使能锁存器(写入状态)后关闭锁存器(缓存本次状态)。

/** *初始化LED,LED全灭 *LED1~8 ==> GPIOC8~15,低电平亮高电平灭 *74HC573锁存器使能端 ==> GPIOD2,高电平使能 */
LED与LCD冲突解决方法

1、编写LED程序(无法保留其他LED状态)

点亮函数点亮前关闭所有。(LED初始化不能先于LCD初始化)
2、更改LCD程序(最优方案)


三个函数添加这三句代码即可。
—>LED的配置详解

2.蜂鸣器

蜂鸣器与JTAG接口的复位脚共用PB4,但默认为JTAG接口的复位脚(内部上拉,上电输出高电平);APB2总线控制时钟,推挽输出控制开关;非比赛考点

/** *初始化蜂鸣器,关闭蜂鸣器,默认上电为JTRST功能,蜂鸣器关闭 *Buzzer ==> GPIOB4,低电平打开高电平关闭 *使能端口复用功能,禁止JTRST功能 */

3.独立按键

APB2总线控制时钟,上拉输入读取。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin):读取端口输入电平状态,高电平返回1低电平返回0。
三行代码扫描函数状态机扫描函数必须和定时器配合,定时器每10ms执行按键扫描。标志位可放于SysTick_Handler()定时,按键处理必须紧跟按键扫描,即在同一时间段执行一次。
按键操作:按下、松开、复合、长按、双击。程序中同时有长按与短按判断时,短按使用上升沿触发。

/** *初始化KEY,KEY设置上拉输入,输入速率无需配置,默认复位状态,速率10MHz *KEY1:GPIOA0; KEY2:GPIOA8; KEY3:GPIOB1; KEY4:GPIOB2 *扫描KEY,按下端口读取低电平,松开端口读取高电平 *//** *扫描KEY,按下端口读取低电平,松开端口读取高电平 *KEY1:0x01; KEY2:0x02; KEY3:0x04; KEY4:0x08 *g_rising判断单双击,g_key_state判断长短按与单双键 */

4.LCD

资料包提供例程,变量通过sprintf函数整理后通过显示函数展示在LCD,需包含stdio.h头文件。2.4寸显示屏单行显示最大值为20英文字符,sprintf函数(结尾自动加\0)调用数组大小不能超过20,格式化字符串不大于20个英文字符(包括空格和字符串结尾的结束符
sizeof 计算的是变量的大小,而 strlen 计算的是字符串的长度,前者不受字符 \0 影响,后者以 \0 作为长度判定依据。
—>利用 strlen 和 sizeof 求取字符串长度注意事项
LCD显示中sprintf((char*)string, “%s”);"%s"格式符的最大长度为19,其他格式符时最大长度为20。
sprintf函数使用:"%02d:%02d:%02d"可用于在数值前显示0,2表示%d占2位,02表示%d占两位,且数值不足两位时前面添0补足(数值长度大于数字则该用法无效)。
在官方给的参考资料里面介绍了分辨率是240x320,lcd一共分为10行,20列,所以一个字符的高实际上是24*16,所以我们可以看到lcd.h宏定义里面每一行之间的差值就是24,那么每一列之间的差值就是16,实际上表示一列的时候是反着来的,320表示第一列,320-16表示第二列,那么320-(16 * i)表示第i列。
—>点阵图、矢量图、像素图、位图图像、位元块传输
—>sprintf()函数的用法

LCD字符高亮颜色显示

void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii);
数字显示:LCD_DisplayChar(Linex, 320 - (16 *y), variable / 10 + 48);
LCD_DisplayChar(Linex, 320 - (16 *y + 1), variable % 10 + 48);
Ascii码:数字0-9 —> 码值48-57,大写字母A-Z —> 码值65-90,小写字母a-z —> 码值97-122

voidSTM3210B_LCD_Init(void);/*LCD初始化*/voidLCD_SetTextColor(vu16 Color);/*LCD文本颜色*/voidLCD_SetBackColor(vu16 Color);/*LCD文本区域背景颜色*/voidLCD_ClearLine(u8 Line);/*清屏指定行*/voidLCD_Clear(u16 Color);/*指定颜色清屏*/voidLCD_SetCursor(u8 Xpos,u16 Ypos);/*锁定显示起点坐标*/voidLCD_DrawChar(u8 Xpos,u16 Ypos,uc16*c);/*画字符*/voidLCD_DisplayChar(u8 Line,u16 Column,u8 Ascii);/*LCD展示字符*/voidLCD_DisplayStringLine(u8 Line,u8*ptr);/*指定行展示字符串*/voidLCD_SetDisplayWindow(u8 Xpos,u16 Ypos,u8 Height,u16 Width);/*设置显示区域大小*/voidLCD_WindowModeDisable(void);/*退出窗口模式(全屏)*/voidLCD_DrawLine(u8 Xpos,u16 Ypos,u16 Length,u8 Direction);/*画线*/voidLCD_DrawRect(u8 Xpos,u16 Ypos,u8 Height,u16 Width);/*画矩形框*/voidLCD_DrawCircle(u8 Xpos,u16 Ypos,u16 Radius);/*画圆*/voidLCD_DrawMonoPict(uc32*Pict);/*画单色图片*/voidLCD_WriteBMP(u32 BmpAddress);/*显示BMP位图*/voidLCD_DrawBMP(u32 BmpAddress);/*画BMP位图*/voidLCD_DrawPicture(constu8*picture);/*画图片*/

5.TIMER

分频寄存器(PSC)数值为0表示1分频,设置PSC寄存器值:需要的分频数-1;计数器达到自动重装载值后再加1则产生溢出,自动重装载寄存器(ARR)中再次写入自动重装载值,设置自动重装载寄存器(ARR)数值:需要的计数值-1。
通用定时器:定时器2~5,各4通道;
高级定时器:定时器1和8,各4通道;
基本定时器:定时器6和7,直接连接驱动DAC,没有引脚复用;
TIM_RepetitionCounter对高级定时器有用;
定时器在发生中断源事件时进入中断服务函数,更新中断(溢出,TIM_IT_Update)、捕获/比较事件(CNT = CCRx,TIM_IT_CCx等,事件产生使TIMx_EGR寄存器置位;只有更新事件(UEV,发生更新中断)或TIMX_EGR寄存器的UG位置位触发定时器计数初始化,所有寄存器被更新;
预装载寄存器:只有发生更新事件才将数据更新至影子寄存器(真正的装载寄存器)。
设置中断源:void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

/** *定时器2初始化 *预分频系数(计数时钟频率 = f / (PSC + 1)):PSC - 1; 自动重装值(计数溢出重回0后产生中断):ARR - 1;向上计数法,时钟1分频; 定时器中断配置并使能 *中断优先级分组,中断通道选择并使能,中断等级设置 *默认复位APB1时钟:36MHz(2分频),通用定时器时钟:72MHz(APB1预分频系数不等于1) *//** *定时器2中断 *定时器溢出:定时器中断标志位置1,需软件手动清0 */

—>stm32定时器中断类型
—>STM32定时器中的更新操作与更新事件
—>STM32中断服务函数的编写注意事项1
—>STM32中断服务函数的编写注意事项2
—>stm32定时器误区

6.实时时钟

蓝桥杯嵌入式开发板的RTC只能使用LSI即内置RC振荡器。实时时钟可不用开启中断使用。
RTC不在APB1和APB2时钟总线上,需单独配置时钟使能;LSI时钟40KHz,4000分频(系数3999)得计数频率1s。
RTC时间存储以定时器计数总值存储,每计数加一为时间1s,60s = 1min,3600s = 1h,0x0001517F为23:59:59,0x00015180为00:00:00;
void RTC_SetCounter(uint32_t CounterValue):设置初始时间(单位秒)hour * 3600 + minute * 60 + second;
RTC中断服务函数为RTC_IRQHandler(),不是RTCAlarm_IRQHandler();

/** *RTC初始化 *配置RTC中断,开启触发每秒中断 *备份寄存器(BKP)与电源管理(PWR)时钟使能,使能BKP,复位BKP寄存器, *使能LSI时钟,等待LSI使能完毕,配置LSI为RTC时钟源,RTC时钟使能, *等待APB1和RTC时钟同步,等待对RTC操作完成,设置RTC频率,等待完成,设置计数值(初始时间),等待完成 *//*实时时钟获取,计算多少个3600秒(时)、除去多少个3600秒后余多少个60秒(分)、除去多少个60秒后余多少个秒(秒)*//*每秒触发中断,判断是否计数达到23时59分59秒*/

—>stm32之备份寄存器(BKP)应用(侵入检测中断)
—>STM32电源管理(PWR)

7.USART

数据发送使用字符串发送函数,或者重定义fput函数然后使用printf,只要程序中有printf重映射函数必须勾选Use MicroLIB选项,否则程序无法运行。
用串口调试助手给单片机以字符串的形式发送数据时,结尾是不默认添加’\0’。
半主机模式就是通过仿真器实现开发板在电脑上的输入和输出,单片机程序运行应脱离仿真器关闭半主机模式。
数据接收开启串口接收中断
USART_FLAG_TC和USART_FLAG_TXE区别
TC和TXE在复位默认置1,但TXE在对发送寄存器(USART_DR)写操作后被清零,TC要先读状态并对寄存器写操作才进行清零,两者都可软件清零,所以上电后使用TC来判断字符串传输时,如果未清零(软件清零或软件序列清零)会导致首字母被覆盖而不显示,而TXE在首字母转移到发送寄存器后立即清零不会被覆盖。除了复位首字母问题,程序运行过程中会被自动被特性规则清零,不必手动清零。

/*添加该内容,不必勾选Use MicroLIB选项*/#pragmaimport(__use_no_semihosting)struct__FILE{inthandle;};FILE __stdout;_sys_exit(intx){x=x;}/***********************************//** *初始化USART2,IO口配置(APB2总线时钟),串口配置(APB1总线时钟),中断配置 *发送端TX2 ==> PA2,复用推挽输出,50MHz;接收端RX2 ==> PA3,浮空输入 *波特率:f_baudrate, 字节长度:8bit, 停止位:1位, 校验位:无, 模式:接收和发送, 硬件数据流控制:无 *中断通道:串口2中断, 最高抢占和响应优先级 *//** *发送字符串 *发送标志位使能,发送字符数据,返回字符 *USART_FLAG_TC表示传输完毕,USART_FLAG_TXE表示发送缓冲区空,无特殊情况均使用USART_FLAG_TXE效率快 *注意:while和if后的括号中无论是it+还是++i,都先执行括号内的自增减,再执行大括号内的语句 *//*重定义fputc函数(printf函数调用)*//** *串口2接收中断服务函数 *注意:接收字符串结尾必须加换行符(\r\n) */


—>对原子哥USART实验中printf重定向进行分析
—>USART与UART的区别
—>串口接受不定长数据方法
—>printf重映射解释
—>printf函数重定义
—>printf输出串口助手、防卡死办法
—>上电发送字符串首字母问题

8.24C02

写数据的时候需要注意,E2PROM是先写到缓冲区(发送完Stop),然后再“搬运到”到掉电非易失区(进入写入周期),这个过程让它应答是没有响应(时间需要最大10ms,不用芯片时间不同,开发板上M24C02时间为5ms),直到写入周期完成。
AT24C02是Ateml公司的2KB的电可擦除存储芯片,M24C02是ST公司的2KB的电可擦除存储芯片,区别在于AT24C02支持8字节页写、M24C02支持16字节页写
页写入:一次性连续写入最多8字节(24C02一页为8字节,起始地址为0x00,注意超过页边界会自动从头覆盖)到缓冲区后,再等待一个写入周期,多字节“搬运到”到掉电非易失区;
连续写和连续读时地址自动加1,一页8字节,翻页需要重新指定新的页地址。
SCL -> GPIOB6,SDA -> GPIOB7

/** *I2CWaitAck()已修改 *启动I2C总线;开启写操作0xA0,写入指定的地址;再次启动I2C总线;开启读操作0xA1,读取指定地址内数据,每次发送字节后需等待I2C总线应答,停止I2C总线 *连续读地址自动加1直到最后一个地址 *//** *启动I2C总线;开启写操作0xA0,写入指定的地址,向指定地址写入数据,每次发送字节后需等待I2C总线应答,停止I2C总线 *连续写地址自动加1直到页边缘,AT24C02缓冲区到非易失区需要等待5ms */

—>AT24C02详细介绍
—>页写入
—>IIC通信协议总结
—>E2PROM读写函数
—>不同数据类型读写

9.ADC

STM32的ADC的输入时钟不得超过14MHz
ADC转换就是输入模拟的信号量转换成数字量。读取数字量必须等转换完成后,完成一个通道的读取叫做采样周期。采样周期一般来说=转换时间+读取时间,而转换时间=采样时间+12.5个时钟周期。采样时间是你通过寄存器告诉STM32采样模拟量的时间,设置越长越精确
STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期
为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降
单次模式下需要软件或外部事件再触发,ADC才进行下一次转换
STM32的ADC转换时间是12.5个ADC时钟.
然后采样时间可以设置为1.5~239.5个ADC时钟.
采样频率=ADC时钟/(采样时间+12.5)

/** *初始化ADC,使能ADC,校准ADC *GPIOB0 ==> 电位器R37,模拟输入,独立模式,单通道单次转换,软件触发,数据右对齐 *复位校准和开始校准需等待完成 *//** *获取电压值 *PB0:ADC通道8,0 ~ 3.3V,12位ADC(2^12 - 1 = 4095) *ADC_FLAG_EOC,读取ADC规则数据寄存器(ADC_DR)后自动清除 *//** *获取温度值, *内部温度传感器:ADC1通道16,12位ADC(2^12 = 4096),采样时间大于17.1us,温度值 = (1.43 - Vsense)V / 4.478mV/℃ + 25 */

—>为什么STM32的ADC转换时钟不能大于14MHz
—>STM32的单双ADC单双通道配置
—>STM32的ADC配置详解

10.PWM & TIM_OC

PWM模式(TIM_OCMode_PWMx):可输出多种波形, ARR设置频率,CCR设置占空比,占空比可达到0%或100%。STM32的每个通用定时器都有4个输入捕获的通道,分别是TIMx_CH1、TIMx_CH2、TIMx_CH3、TIMx_CH4,单通道频率和占空比可以任意设置,但同意定时器四个通道只能输出频率相同、占空比可变的PWM,起始相位不能设置。复用推挽输出
PA1->TIM2_CH2、PA2->TIM2_CH3(USART2)、PA3->TIM2_CH4、PA6->TIM3_CH1、PA7->TIM3_CH2、
TIM_CtrlPWMOutputs(TIMx,ENABLE)函数只对高级定时器有效。

/** *定时器2通道2PWM模式初始化 *复用推挽输出,定时器设置为1us计数,重装载值为1M/pwm频率,pwm周期为1/f_freq(f_freq >= 16),占空比为f_duty *TIM2_CH2:PA1,输出捕获x(TIM_OCx)意思是定时器通道x,每次TIM_CNT = TIM_CCRx和TIM_CNT = TIM_ARR时,输出电平极性反向 */voidPWM_Init(u32 f_freq,u8 f_duty)/** *定时器2通道2输出比较模式初始化 *复用推挽输出,定时器设置为1us计数,重装载值为1M/pwm频率,pwm周期为1/f_freq(f_freq >= 16),占空比为f_duty *TIM2_CH2:PA1,输出捕获x(TIM_OCx)意思是定时器通道x,每次TIM_CNT = TIM_CCRx时,输出电平极性反向 *//** *输出捕获中断服务函数 *通过不断更改TIM_Pulse(CCR1)值改变频率和占空比 */


输出比较模式(TIM_OCMode_Toggle): 只能输出方波,单通道ARR设置频率,CCR设置每个通道的初始相位,频率和起始相位可以任意设置,占空比不能设置。输出频率为理论计算值一半;使用定时器捕获中断时,同一定时器的四个通道可以分别输出频率和占空比可变的PWM,但占空比不能达到0%或100%。

修改占空比:void TIM_SetComparex(TIM_TypeDefTIMx,uint16_t Compare2);(x=1,2,3,4)。
修改频率:void TIM_SetAutoreload(TIM_TypeDef
TIMx, uint16_t Autoreload);
CCRx值改变时立即生效(Disable)或发生更新事件后生效(Enable):TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);(x=1,2,3,4),比较输出可调PWM必须CCRx值改变时立即生效。
—>PWM配置
—>PWM频率与占空比详解
—>STM32输出比较模式和PWM模式比较
—>Keil5中的虚拟示波器进行软件仿真
虚拟示波器只能仿真程序,遇到LCD初始化或LCD相关函数会进入死循环,无法仿真后续程序引脚电平变化。

11.TIM_IC

同一定时器可以不同通道不同功能。
修改捕获的触发方式使用的函数是:
TIM_OC2PolarityConfig(TIM3,TIM_ICPolarity_Rising);
输出比较也适用于输入捕获,因为他们操作的实际上是同一个地方

/** *TIM3_CH2:PA7,浮空输入,上升沿触发中断 *//** *捕获到上升沿定时器清零,设置下次捕获下降沿触发 *捕获到下降沿记录时间,设置下次捕获上升沿触发 *捕获到上沿记录时间,单周期脉冲捕获结束等待捕获开始 */

—>STM32定时器中的输入捕获滤波器

12.DMA

—>DMA详解

13.数码管

/** *初始化PA1~3 *PA1:SER(数据输入),每输入一位数据,SCK上升沿有效一次,直至八位输入完毕 *PA2:RCLK(移位寄存器与存储寄存器(锁存)的开关),上升沿时移位寄存器数据进入存储寄存器,下降沿存储寄存器数据不变 *PA3:SCK(数据传输控制),上升沿时数据寄存器数据移位,下降沿移位寄存器数据不变 *//** *共阴数码管 *数据传输方向:SER1(PA1) -> DH'1 -> SER2 -> DH'2-> SER3 -> DH'3,传输数据顺序先DS3再DS2后DS1 */

—>蓝桥杯嵌入式扩展板学习之数码管

14.ADC按键

/** *初始化ADC1_CH5和PA5 *PA5连接AKEY *//** *读取ADC值 *通过按键按下分压值不同判断哪个按键按下 *//*三行代码按键扫描法*/


—>蓝桥杯嵌入式扩展板学习之ADC按键

15.DS18B20

/*初始化PA6(TDQ),上拉输入保证充足供电*//** *读取DS18B20温度值 *复位,写入OW_SKIP_ROM(0xCC),跳过ROM,写入DS18B20_CONVERT(0xCC),开始转换,等待750ms *复位,写入OW_SKIP_ROM(0xCC),跳过ROM,写入DS18B20_READ(0xBE),开始分别读取高八位和低八位(先低后高) *高八位(高五位符号位,后三位整数部分2^6~2^4),低八位(高四位整数部分2^0~2^3,后四位小数部分2^-1~2^-4),温度值 = 总16位 * 0.0625(==> / 16) */



—>蓝桥杯嵌入式扩展板学习之DS18B20

16.光敏电阻

光照越强阻值越小,阻值越大电压越大;
RP7电位器电阻过大可能造成暗度无影响,TRDO恒为低电平,RP7电位器电阻过小可能造成亮度无影响,TRDO恒为高电平。

/** *初始化PA3、PA4和ADC1_CH4 *PA3连接TRDO,输出数字量0或1;PA4连接TRAO,输出模拟量ADC转换值 *//** *获取ADC转换值 *0:返回电压值(参考电压VDD = 3.3V);1:返回电阻值(参考电阻R46 = 10K) */


—>蓝桥杯嵌入式扩展板学习之光敏电阻

17.ADCx2双通道

/** *初始化ADC1_CH4与ADC1_CH5 *PA4(AO1->PR5):ADC1_CH4;PA5(AO2->PR6):ADC1_CH5 *//*获取电压值(按先后顺序单通道采集),PR5\PR6(MAX:10K)与100分压*/

—>蓝桥杯嵌入式扩展板学习之ADCx2

18.DTH11

unsigned int dht11_read(void)函数:返回32位值,高十六位(高8位整数,低8位小数)为湿度值(%),低十六位(高8位整数,低8位小数)为温度值(摄氏度),由于温湿度的分辨率原因,读取时只需要整数部分即可。
采样周期必须大于2秒

/*初始化PA7(HDQ)*//*获取温湿度值,高低16位分别湿度值和温度值*/


—>蓝桥杯嵌入式扩展板学习之DHT11

19.TLC551测量

扩展板电位器控制产生频率与产生占空比。

/** *TIM2_CH2:PA1(PULS1->RP3),TIM2_CH3:PA2(PULS2->RP4),TIM3_CH1:PA6(PWM1->RP1),TIM3_CH2:PA7(PWM2->RP2) *浮空输入,上升沿触发中断 *定时器每个通道需要单独配置 *//** *定时器多通道输入捕获使用分时捕获 *捕获到上升沿定时器清零,设置下次捕获下降沿触发 *捕获到下降沿记录时间,设置下次捕获上升沿触发 *捕获到上沿记录时间,单周期脉冲捕获结束等待捕获开始 */

—>蓝桥杯嵌入式扩展板学习之TLC551测量

20.LIS302DL

/** *I2C总线初始化 *更改为RCC_APB2Periph_GPIOA时钟使能 *宏定义I2C_PORT改为GPIOA,SDA_Pin改为GPIO_Pin_5,SCL_Pin改为GPIO_Pin_4 *//** *写入LIS302DL寄存器函数 *写指令:0x38,将数据写入特定地址 *//** *配置LIS302DL *向CTRL_REG1寄存器(0x20)写入指令0x47:配置加速度采集频率200Hz,普通功耗模式,灵敏度为18mg/LSB,非自检模式,使能XYZ轴加速度采集 *//** *读取LIS302DL寄存器函数 *写指令:0x38,将数据写入特定地址;读指令:0x38,将数据从特定地址读取 *//** *读取坐标加速度 *判断STATUS_REG寄存器(0x27)的数据更新标志位是否为1(0x08),更新则读取XYZ轴加速度相对值(0~255) *X轴加速度输出寄存器地址:0x29,Y轴:0x2B,Z轴:0x2D */

—>蓝桥杯嵌入式扩展板学习之LIS302DL

蓝桥杯嵌入式旧板资料包免费下载

蓝桥杯嵌入式旧板程序代码免费下载

本人通过许多大牛博客自学在大二获得蓝桥杯嵌入式国赛三等奖,但自身知识体系沉淀不足,借此博客创作过程继续深入学习扩展知识,借鉴蓝桥杯嵌入式相关的大牛介绍,让自己的技术更进一步。
—>蓝桥杯嵌入式推荐博客1
—>蓝桥杯嵌入式推荐博客2

************************************************

HAL库版本

—>STM32CUBEMX代码格式优化

定时器

G4系列通用定时器TIM2和TIM5的重装载值可达到32位
—>HAL库定时器配置

串口

每次中断只能接收一个字符

输入捕获

输入通道:需要被测量的信号从定时器的外部引脚 TIMx_CH1/2/3/4 进入,通常叫 TI1/2/3/4,在后面的捕获讲解中对于要被测量的信号我们都以 TIx 为标准的叫法
捕获通道:捕获通道就是输入捕获整体结构图中的 IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器 CCR1/2/3/4,当发生捕获的时候,计数器 CNT 的值就会被锁存到捕获寄存器。
输入通道是用来输入信号的,捕获通道是用来捕获输入信号的通道,一个输入通道的信号可以同时输入给两个捕获通道。
PWM 输入模式一个输入通道(TIx)会占用两个捕获通道(ICx),所以一个定时器在使用 PWM 输入的时候最多只能使用两个输入通道(TIx),如下图。

PWM 信号由输入通道 TI1 进入,信号会被分为两路,一路是 TI1FP1,另外一路是 TI2FP2。其中一路是测周期,另一路是测占空比。由此,定时器的输入捕获有两个功能,直接捕获模式和间接捕获模式;
直接模式:只能捕获本身通道的脉冲信号;
间接模式:可以捕获此定时器每个通道的脉冲信号。
auto-reload precload=Disable:自动重装载寄存器写入新值后,计数器立即产生计数溢出,然后开始新的计数周期
auto-reload precload=Enable:自动重装载寄存器写入新值后,计数器完成当前旧的计数后,再开始新的计数周期
—>输入捕获功能配置

ADC

—>adc精度

RTC

读取时间需要将时间和日期一起读取出来。
HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);
HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);


# 总结 蓝桥杯嵌入式语言相关博客网络资料已经较为齐全,以上仅为本人所学的知识总结,本文未涉及未学习到的知识点,其中链接网址仅作记录使用,如有侵权或内容有误,敬请联系斧正。若读者觉得本文对学习有所帮助,不妨Give a like,Respect!!!
http://www.jsqmd.com/news/881267/

相关文章:

  • 从安装到精通:BetterTweetDeck完整使用手册(2023最新版)
  • 网盘下载加速神器LinkSwift:告别龟速下载的5分钟完整指南
  • vczh_toys Linq库进阶:复杂数据处理的8个实用案例指南
  • 别再等电池报废!用Python+Sklearn,仅需100次循环数据就能预测电池寿命(附完整代码)
  • ComfyUI终极UI增强指南:7个免费工具让你的AI绘画效率翻倍
  • 可视化数据集构建指南:从概念到实践,驱动图表智能生成与理解
  • gcvis高级功能:自定义图表、数据导出与API集成终极指南
  • wolkenkit数据存储配置:PostgreSQL、MySQL、MongoDB实战指南
  • Unity 2022 LTS + Photon Fusion 2:手把手教你搭建第一个多人联机Demo(含完整代码)
  • 时间序列预测实战:从LightGBM到GNN与强化学习的算法选型指南
  • 海尔智能家居设备接入HomeAssistant:打造一体化智能家居控制中心
  • 机器学习解码结直肠癌基因协同作用:从WNT通路到联合治疗新靶点
  • 2026年4月头部火锅品牌推荐,地摊火锅/重庆火锅/成都火锅/社区火锅/牛肉火锅/美食/附近火锅,火锅品牌推荐 - 品牌推荐师
  • 如何为Tesla-Menu添加自定义覆盖?终极开发者入门指南
  • 融合物理与AI:基于DtN映射与FEM的椭圆型PDE反问题自监督求解框架
  • 告别音乐平台切换:开源音源聚合方案如何重塑你的听歌体验
  • 从零构建智能对话工作流:SillyTavern脚本系统的深度应用指南
  • JoyCon-Driver 多控制器管理:同时连接4个 JoyCons 的配置指南
  • Unity Android构建报错SDK version is 0的根因与精准修复
  • 2026年4月市面上靠谱的udb测试直销厂家推荐,疲劳曲线测试/压铸件模流分析,udb测试直销厂家推荐 - 品牌推荐师
  • ImageSearch部署指南:从开发环境到生产环境的完整迁移策略
  • OpenPilot深度部署指南:从架构解析到生产级调优
  • G-Helper终极指南:华硕笔记本轻量控制神器,告别Armoury Crate臃肿
  • Forge中的上下文压缩:处理长对话的高效方法
  • Linux服务器升级OpenSSL 3.2.0后,为什么我的curl命令不能用了?一个软链接引发的‘血案’
  • WOFOST模型参数太多看不懂?一篇带你读懂关键参数设置与避坑指南(以小麦/玉米为例)
  • Unity银河战士类游戏开发:状态机、关卡拓扑与Boss行为树实战
  • Hindsight观察系统终极指南:AI智能体的自动知识整合机制 [特殊字符]
  • GHelper终极指南:轻量级华硕笔记本控制工具完整教程
  • vue-axios-github解密:5分钟理解axios拦截器实现请求/响应统一处理