蓝桥杯——嵌入式学习日记

因为lED和LCD共用PC8~PC15引脚,要通过锁存(LE)和(GPIOC->ODR)来避免LED和LCD引脚冲突

修改点:

  • main.c中,GPIO初始化引脚后,LE(PD2引脚低电平锁存,退出透明模式,LCD的输出就无法影响LED引脚的状态)
  • LCD_DisplayStringLine();

  • LCD_Clear()

定时器中断

定时器功能

定时器频率和周期公式

  • PSC(预分频系数): 1 / f == T, 乘上(PSC+1) 得到执行一次累加操作的实际周期,再乘上(ARR+1)等于中断周期
  • 预分频理解: 假设原本1ms执行一次累加, PSC == 2, 则当前变成2ms才执行一次累加(另外的1ms分给了别的任务)
  • 时钟配置
    - 通过STM32CubeMX,配置TIM2(通用定时器)的参数(Fsystem = 80MHz = 80 000 000)
    假设定时中断周期要求 1s , 则 ARR+1=8000 , PSC+1 = 10000

使能定时中断

c 复制代码
//定时中断需要使能
   HAL_TIM_Base_Start_IT(&htim2);  //HAL_TIM_Base_Start_IT函数用于以中断模式启动定时器

长按键、短按键(使用TIM3)



利用cnt计时

本质就是将计算 T 公式里的: ARR 代替为 CNT(计数值)------ T = 1 / f = CNT * (PSC + 1) / f

LCD高亮显示

c++ 复制代码
//按键4通过循环取余数,控制lcd某行高亮显示
static uint16_t temp_line = 0;
void Hight_light_lcd_line(){
     
	key_s4 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

	if(key_s4==RESET && k4_last_state==SET){  //按下B4
	    temp_line++;
		temp_line%=3;
		HAL_Delay(200);
	}
	
	//控制功能栏轮流高亮显示
	if(temp_line==0){
	   
       //sprintf();   用于写入字符串到字符数组
	   LCD_SetBackColor(Red);  //该行以下的背景颜色是红色
	   sprintf(text, "    Hello, Vodka!     ");
	   LCD_DisplayStringLine(Line3, (uint8_t*) text );
		
	   LCD_SetBackColor(Black);		//该行以下的背景颜色是黑色
	   sprintf(text, "      Count: %d        ", Count);
	   LCD_DisplayStringLine(Line4, (uint8_t*) text);
	   
		
	   sprintf(text, "   LightMode: %d        ", lightMode);
	   LCD_DisplayStringLine(Line5, (uint8_t*) text);

	}
	else if(temp_line==1){
	   //sprintf();   用于写入字符串到字符数组
	   sprintf(text, "    Hello, Vodka!     ");
	   LCD_DisplayStringLine(Line3, (uint8_t*) text );
		
	   LCD_SetBackColor(Red);	
	   sprintf(text, "      Count: %d        ", Count);
	   LCD_DisplayStringLine(Line4, (uint8_t*) text);
	   LCD_SetBackColor(Black);	
		
	   sprintf(text, "   LightMode: %d        ", lightMode);
	   LCD_DisplayStringLine(Line5, (uint8_t*) text);	
	}
    else if(temp_line==2){
	   //sprintf();   用于写入字符串到字符数组
	   sprintf(text, "    Hello, Vodka!     ");
	   LCD_DisplayStringLine(Line3, (uint8_t*) text );
		
	   sprintf(text, "      Count: %d        ", Count);
	   LCD_DisplayStringLine(Line4, (uint8_t*) text);
	   
	   LCD_SetBackColor(Red);	
	   sprintf(text, "   LightMode: %d        ", lightMode);
	   LCD_DisplayStringLine(Line5, (uint8_t*) text);
	   LCD_SetBackColor(Black);	
	}
	//LED闪烁,间隔两秒闪烁一次
	light_led(3,lightMode%2);
   
}

PWM波形

原理

占空比:高电平持续时间占整个周期时长的比值
PWM频率和占空比的概念:占空比由捕获比较寄存器(CCR)决定,而频率由ARR和PSC共同决定。不同的PSC和ARR组合可以得到相同的频率,只要它们的乘积相同。例如,PSC=1和ARR=1000,与PSC=2和ARR=500,得到的频率是一样的,但占空比的调节范围可能不同,因为ARR的值不同。

CubeMX配置

初始化

CCR(输出比较寄存器)

输入捕获测量引脚输出PWM波形

通过计算两个中断之间CNT差值(capture_value),得出中断周期(捕获周期)

捕获周期计算公式

信号发生器

PWM输出引脚和输入捕获引脚,板子上的引脚R37~R40分别是:电压采集1、电压采集2、频率输出1(PB4)、频率输出2(PA15)

例题


TIM17配置(记得配置NVIC)

pwm输入捕获代码

PA1、PA7需要杜邦线连接; PA1配置TIM2的通道2、PA7配置TIM17的通道1

输入捕获555定时器的频率

时钟通道配置

引脚PA15和引脚PB4测量频率输入1和频率输入2

代码

TIM2、TIM16输入捕获中断开启

TIM2、TIM16输入捕获展示

ADC测量

配置ADC1和ADC2

代码实现

USART通信(异步、全双工、字节传输)

配置

类型转换问题

c++ 复制代码
字符类型(char)在算术运算中会被转换为整数类型(int)。
short型会被转换为int型。
float型会被转换为double型以提高精度。
当有符号数与无符号数进行运算时,所有操作数自动转换为无符号类型

字符与字节

存储字符串 "bens in 2023/23/23" 的 char 数组需占用 19 字节,空格也算字符,包含'\0'作为终止符(转义字符\n,\t也算字符)

代码实现(向上位机发送数据)

c++ 复制代码
void UART_Tx_Test(void){
   
   sprintf((char*)uart_tx_text,"Hey~ Vodka~\r\n");	
   HAL_UART_Transmit(&huart1, (uint8_t *)uart_tx_text, strlen(uart_tx_text), 50);  //超时时间限制为50ms
   HAL_Delay(2000); //发送数据间隔时间: 0.1s	
	
}

代码实现(按字节循环接收uart串口数据)

主函数

c++ 复制代码
//util.h
#ifndef __util_h
#define __util_h
//串口接收变量
extern char uart_rx_text[22];
extern uint8_t Rx_Byte;
extern uint8_t Rx_Index;
extern uint8_t Rx_DoneFlag;

//车辆信息(串口接收)
extern char car_type[5];
extern char car_data[5];
extern char car_time[13];

//测试函数                                      
void lcd_test(void);                            
                                                                                            
//ADC测量                                       
void ADC_show(void);                            
	
//ADC测量电压
void ADC_Caculate_Volt(void);

//串口发送测试
void UART_Tx_Test(void);

//串口接收测试(只能通过中断接收)
void UART_Rx_Test(void);

//UART中断数据后续处理(放在主程序里循环)
void uart_data_process(void);
	
#endif


//util.c
//UART中断回调接收数据(第一次中断在主函数)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart){
    if(huart->Instance == USART1){
		uart_rx_text[Rx_Index++] = Rx_Byte;
		//判断接收的字节是否完成
   		if(Rx_Index==22||Rx_Byte=='\n'){
		    Rx_DoneFlag = 1;
		}
		//继续开启下一次中断
		HAL_UART_Receive_IT(&huart1,&Rx_Byte,sizeof(Rx_Byte));
	}
}

//UART中断数据后续处理(放在主程序里循环)
void uart_data_process(void){
   //判断中断接收完毕标志
   if(Rx_DoneFlag==1){
      if(Rx_Index <= 22){   //接收数组长度22字节,除去\0,实际只能存储21个字节
	     sscanf(uart_rx_text, "%4s %4s %10s", car_type, car_data, car_time);
		 //展示数据
		 LCD_SetBackColor(Yellow);
         LCD_SetTextColor(Black);		
		  
          sprintf(rx_display_text,"        UART_Rx           ");
		  LCD_DisplayStringLine(Line0,rx_display_text);		  
		  
		  sprintf(rx_display_text,"    car_type:%s       ",car_type);
		  LCD_DisplayStringLine(Line1,rx_display_text);
		  
		  sprintf(rx_display_text,"    car_data:%s         ",car_data);
		  LCD_DisplayStringLine(Line2,rx_display_text);
		  
		  sprintf(rx_display_text," car_time:%s        ",car_time);
		  LCD_DisplayStringLine(Line3,rx_display_text);		  
	  }
	  else{
	     sprintf(rx_display_text,"        Rx_Error\r\n          ");
		 HAL_UART_Transmit(&huart1, (uint8_t*)rx_display_text, strlen(rx_display_text), 50); 
	  }
	  //重置相应标志
	  Rx_DoneFlag = 0;
	  Rx_Index = 0;
	  memset(uart_rx_text,0,strlen(uart_rx_text));
   }
}

通过定时器,UART串口接收不定长的数据

原理

传送一个字节花费的时间,转化为CNT的值来判断

间隔指定时间读取一个数据

判断结束的标志:最后一个位的时间大于1.5ms

配置

TIM4:内部时钟、波特率:9600、 开启中断、 PSC: 8000-1

串口中断开启、时钟使能

中断处理、中断回调


自行编写




IIC

IIC原理图

非易失性存储器

从机地址

读写位:1是读、2是写

代码实现


RTC实时时钟

设置(读取)时间、日期,设置闹钟

RTC配置


代码实现


相关推荐
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习