蓝桥杯嵌入式第六届真题实战练习
一、CubeMX基础配置
1.Point & Configuration
- 时钟配置
- 串口debug
2.Clock Configuration
时钟树配置
24→80
3.Project Manager
- Project
- Code Generator
二、真题与解题流程图
三、CubeMX底层驱动配置
systick(10ms)
ADC
GPIO和LCD
这里这不详述。
UART
RTC
RTC用作时钟,选择HSE为高速外部时钟,得到750KHz,需要/125/6000得到1Hz。
四、代码程序
- 文件介绍
在keil上创建bsp组,然后包含我的文件,总共有interrupt.h和interrupt.h,用作写函数回调函数;
lcd.h和lcd.c及font.h,移植官方lcd例程文件:资源数据包_嵌入式(G431)_2021\5-液晶驱动参考例程\HAL_06_LCD;
badc.c和badc.h,用作ADC获取电位器R37电压值的封装函数,badc命名避免与官方库adc.c的命名冲突;
i2c - hal.c和i2c - hal.h,移植了官方i2c例程文件:资源数据包_嵌入式(G431)_2021\1-底层驱动代码参考
在main.h中我类型定义了uint和uchar。
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx_hal.h"
#include "stm32g4xx_ll_pwr.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
typedef unsigned uint;
typedef unsigned uchar;
/* USER CODE END Includes */
- bsp代码
interrupt.h
#ifndef __INTERRUPT_H
#define __INTERRUPT_H
#include "main.h"
struct keys
{
uchar key_pro;
uchar key_sta;
uchar key_flag;
};
void led_proc(uchar ds_led);
#endif
interrupt.c
#include "interrupt.h"
#include "usart.h"
struct keys key[4]={0};
void led_proc(uchar ds_led)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, ds_led<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM1)
{
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch(key[i].key_pro)
{
case 0:
{
if(key[i].key_sta==0)
{
key[i].key_pro=1;
}
}
case 1:
{
if(key[i].key_sta==0)
{
key[i].key_pro=2;
key[i].key_flag=1;
}
else
{
key[i].key_pro=0;
}
}
case 2:
{
if(key[i].key_sta==1)
{
key[i].key_pro=0;
}
}
}
}
}
}
uchar rxdata[30];
uint8_t rxdat;
uchar rxpointer;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
rxdata[rxpointer++]=rxdat;
HAL_UART_Receive_IT(&huart1,&rxdat,1);
}
badc.h
#ifndef __BADC_H
#define __BADC_H
#include "main.h"
double getADC(ADC_HandleTypeDef *hadc);
#endif
badc.c
#include "badc.h"
double getADC(ADC_HandleTypeDef *hadc)
{
uint ADC;
HAL_ADC_Start(hadc);
ADC=HAL_ADC_GetValue(hadc);
return ADC*3.3/4027;
}
i2c - hal.h
#ifndef __I2C_H
#define __I2C_H
#include "main.h"
void I2CStart(void);
void I2CStop(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(void);
void I2CSendNotAck(void);
void I2CSendByte(unsigned char cSendByte);
unsigned char I2CReceiveByte(void);
void I2CInit(void);
void EEPROM_Write(uchar addr,uchar dat); //新增
uchar EEPROM_Read(uchar addr); //新增
#endif
i2c - hal.c
/* 官方i2c - hal.c代码内容 */ //注意:在第一行中,#include "i2c.h"需要改成#include "i2c - hal.h"
void EEPROM_Write(uchar addr,uchar dat) //新增
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
uchar EEPROM_Read(uchar addr) //新增
{
uchar dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return dat;
}
- main.c代码
- 变量声明和函数声明
#include "interrupt.h"
#include "lcd.h"
#include "stdio.h"
#include "badc.h"
#include "string.h"
#include "i2c - hal.h"
extern struct keys key[];
extern uchar rxdata[30];
extern uint8_t rxdat;
extern uchar rxpointer;
uchar led_mode=0; //LED1闪烁预警模式,0为默认开启闪烁预警模式,1为关闭闪烁预警模式
RTC_TimeTypeDef TIME; //RTC 时间结构体
RTC_DateTypeDef DATE; //RTC 日期结构体
uchar view=0; //界面切换
uchar text[30]; //用作sprinf的缓存数组
double k=0.1; // k值,默认0.1
uchar set_hour=10; //设置时间的时钟参数
uchar set_min=20; //设置时间的分钟参数
uchar set_sec=0; //设置时间的秒钟参数
uchar note_hour=0; //默认0小时0分钟0秒钟上报
uchar note_min=0;
uchar note_sec=0;
uchar B2_count=0;
uchar B3_count=0;
void led_turn_off(void);
void key_proc(void);
void disp_proc(void);
void uart_rx_proc(void);
- LED程序(LED1闪烁功能的开启和关闭两种)
void led_turn_off(void)
{
if(led_mode==0) //默认打开闪烁报警功能
{
if(getADC(&hadc2)>3.3*k) //k值通过串口接收改变
{
led_proc(0X01);
HAL_Delay(200);
led_proc(0X00);
HAL_Delay(200);
}
}
if(led_mode==1) //关闭闪烁报警功能
{
led_proc(0X00);
}
}
- 按键程序
void key_proc(void) //按键如果控制LCD界面,要记得清屏
{
if(key[0].key_flag==1) // B1
{
LCD_Clear(Black); //页面清屏
led_mode=!led_mode; //更换状态,关闭闪烁报警功能
key[0].key_flag=0;
}
if(key[1].key_flag==1) // B2
{
B2_count++;
if(B2_count>2)
{
B2_count=1;
}
LCD_Clear(Black); //页面清屏
if(B2_count==1)
{
view=1; //切换到setting界面
}
if(B2_count==2)
{
note_hour=set_hour;
note_min=set_min;
note_sec=set_sec;
view=0; //切换到LCD显示界面
}
key[1].key_flag=0;
}
if(view==1) // B3只在setting界面有效
{
if(key[2].key_flag==1) // B3
{
B3_count++;
if(B3_count>3)
{
B3_count=1;
}
key[2].key_flag=0;
}
}
if(key[3].key_flag==1) // B4
{
if(B3_count==1)
{
set_hour++;
if(set_hour>24)
{
set_hour=0;
}
}
if(B3_count==2)
{
set_min++;
if(set_min>60)
{
set_min=0;
}
}
if(B3_count==3)
{
set_sec++;
if(set_sec>60)
{
set_sec=0;
}
}
key[3].key_flag=0;
}
}
- LCD显示程序(两个界面:LCD显示界面和setting界面)
void disp_proc(void)
{
if(view==0) //LCD显示界面
{
sprintf((char *)text," V1:%0.2fV",getADC(&hadc2));
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf((char *)text," k:%0.1f",k);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
if(led_mode==0)
{
sprintf((char *)text," LED:OFF ");
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
else
{
sprintf((char *)text," LED:ON ");
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
sprintf((char *)text," T:%02d-%02d-%02d",TIME.Hours,TIME.Minutes,TIME.Seconds);
LCD_DisplayStringLine(Line6, (uint8_t *)text);
}
if(view==1) //setting界面
{
sprintf((char *)text," Setting ");
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf((char *)text," %02d-%02d-%02d ",set_hour,set_min,set_sec);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
if(B3_count==1)
{
LCD_SetBackColor(Blue);
LCD_DisplayChar(Line5,(320-(16*5)),set_hour/10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_DisplayChar(Line5,(320-(16*6)),set_hour%10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_SetBackColor(Black);
}
if(B3_count==2)
{
LCD_SetBackColor(Blue);
LCD_DisplayChar(Line5,(320-(16*8)),set_min/10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_DisplayChar(Line5,(320-(16*9)),set_min%10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_SetBackColor(Black);
}
if(B3_count==3)
{
LCD_SetBackColor(Blue);
LCD_DisplayChar(Line5,(320-(16*11)),set_sec/10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_DisplayChar(Line5,(320-(16*12)),set_sec%10+'0'); //LCD的分辨率是240*320,像素是24*16
LCD_SetBackColor(Black);
}
}
}
- 串口接收程序
void uart_rx_proc(void)
{
if(rxpointer>0) //如果有数据传过来
{
if(rxpointer==6) //"k0.2\n"分别为(k 0 . 2 \ n )六个字符
{
if(rxdata[3]=='1')
{
k=0.1;
EEPROM_Write(0,k);
}
if(rxdata[3]=='2')
{
k=0.2;
EEPROM_Write(0,k);
}
if(rxdata[3]=='3')
{
k=0.3;
EEPROM_Write(0,k);
}
if(rxdata[3]=='4')
{
k=0.4;
EEPROM_Write(0,k);
}
if(rxdata[3]=='5')
{
k=0.5;
EEPROM_Write(0,k);
}
if(rxdata[3]=='6')
{
k=0.6;
EEPROM_Write(0,k);
}
if(rxdata[3]=='7')
{
k=0.7;
EEPROM_Write(0,k);
}
if(rxdata[3]=='8')
{
k=0.8;
EEPROM_Write(0,k);
}
if(rxdata[3]=='9')
{
k=0.9;
EEPROM_Write(0,k);
}
char temp[30];
sprintf(temp,(char *)"ok\n");
HAL_Delay(500); //需要延时,不然串口发送太快,可能会发几遍temp
HAL_UART_Transmit(&huart1,(uint8_t *)temp,sizeof(temp)/sizeof(char), 50);
}
else
{
char temp[30];
sprintf(temp,"Error");
HAL_UART_Transmit(&huart1,(uint8_t *)temp,sizeof(temp)/sizeof(char),50); //仅串口测试用:串口发送"Error"
}
}
rxpointer=0;
memset(rxdata,0,30);
}
- 主函数
int main(void)
{
/* USER CODE BEGIN 2 */
led_proc(0x00); //LED初始化
LCD_Init(); //LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim1); //打开定时器1的中断
HAL_UART_Receive_IT(&huart1,&rxdat,1); //打开串口中断
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_RTC_GetDate(&hrtc,&DATE,RTC_FORMAT_BIN); //RTC获取日期
HAL_RTC_GetTime(&hrtc,&TIME,RTC_FORMAT_BIN); //RTC获取时间
led_turn_off();
key_proc();
disp_proc();
if(rxpointer!=0) //串口接收,防止接收不完整
{
uchar temp=rxpointer;
HAL_Delay(1);
if(temp==rxpointer)
{
uart_rx_proc();
}
}
if(TIME.Hours==set_hour && TIME.Minutes==set_min && TIME.Seconds==set_sec) //串口上报,set_hour、set_min、set_sec默认为0-0-0
{
char temp[30];
sprintf(temp,(char *)"%.2f+%.1f+%02d%02d%02d\n",getADC(&hadc2),k,note_hour,note_min,note_sec);
HAL_Delay(1000); //需要延时,不然串口发送太快,可能会发几遍temp
HAL_UART_Transmit(&huart1,(uint8_t *)temp,sizeof(temp)/sizeof(char), 50);
}
}
/* USER CODE END 3 */
}