蓝桥杯嵌入式第六届真题实战练习

蓝桥杯嵌入式第六届真题实战练习

一、CubeMX基础配置
1.Point & Configuration
  1. 时钟配置
    在这里插入图片描述
  2. 串口debug

在这里插入图片描述

2.Clock Configuration

时钟树配置

24→80

在这里插入图片描述

3.Project Manager
  1. Project

在这里插入图片描述

  1. Code Generator

在这里插入图片描述

二、真题与解题流程图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、CubeMX底层驱动配置
systick(10ms)

在这里插入图片描述

在这里插入图片描述

ADC

在这里插入图片描述

GPIO和LCD

这里这不详述。

UART

在这里插入图片描述

在这里插入图片描述

RTC

在这里插入图片描述

在这里插入图片描述

RTC用作时钟,选择HSE为高速外部时钟,得到750KHz,需要/125/6000得到1Hz。

四、代码程序
  1. 文件介绍

在这里插入图片描述

在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 */
  1. 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;
}
  1. 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 */
}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值