蓝桥杯备战(1)——第六届蓝桥杯嵌入式设计省赛赛题
本人是个很菜的嵌入式开发者,仅仅是为了总结我所学的知识和备战比赛,只能作为参考资料,有些地方写得不对请大家多多包涵,在评论下方指出,谢谢大家。
本题用的是CT117E-M4平台做的,主控是STM32G431RBT6,在国信长天官方电买的板子,店家会给例程(这个很重要),用的STM32CUBEMX和keil开发。
1. 第六届蓝桥杯真题
2. 题目的设计思路图
我读完题目以后,绘制了一个大致的程序设计的框图:
这个图画得有点草率,但是大体结构上是基本正确的,接下来我会按照这个思路进行该题的编程。
3.配置基本外设与程序编写
1)外设的配置
本题需要使用到的外设有ADC、RTC、串口、E2PROM(I2C通信)、GPIO(LED灯和按键)和LCD。所以,我先使用STM32CUBEMX进行配置(注意,I2C和LCD的用的是买来板子给的例程,例程的头文件里面都已经对这两个外设进行了配置,直接调用即可,不需要再CUBEMX中配置),配置图如下:
对配置里面的几个细节进行说明:
- 串口配置好后,一定要打开中断,并且把波特率配置成9600。
- 按键我采用扫描的方式,没有采用中断(我习惯能不用中断就用扫描)
- PB7,PB8是STM32和E2PROM芯片的通信引脚,也是I2C引脚,需要初始化,因为例程给的头文件没有初始化的代码,配置成OUTPUT,参数默认即可。
- 我采用了RTC来实现时钟,时钟源用的是HSE高速时钟,所以RTC的分频系数需要调整,大小根据频率大小来设置(一定要算过)。
- 板子上的LED是共阳极的,按键都是接地的 。
2)代码的编写
代码中很多都参考了买板子时店家给的例程,如果没有例程的话,看这个代码困难比较费劲。
- ADC的代码实现
最简单的先开始,首先是ADC的代码编写。因为采用HAL库,所以直接用就可以,我定义了一个获取ADC值的函数:
uint16_t getADC(void)
{
uint16_t adc = 0;
HAL_ADC_Start(&hadc2);
adc = HAL_ADC_GetValue(&hadc2);
return adc;
}
ADC的值在LCD显示的代码:
sprintf((char *)str2, " V1:%.2f",getADC()*3.3/4096);
LCD_DisplayStringLine(Line1,(uint8_t *)str2);
- 串口的代码实现
其次,是串口,串口有两部分,接收和发送,首先是接收部分,接收采用串口中断的方法,这里只要判断第四个字符是多少就可以确定k值的大小了:
HAL_UART_Receive_IT(&huart1,rx_buf,4);
if(rx_buf[3] == '1')
{
k =0.1;
x24c02_write(0,k);//将k值写入E2PROM
}
if(rx_buf[3] == '2')
{
k =0.2;
x24c02_write(0,k);
}
if(rx_buf[3] == '3')
{
k =0.3;
x24c02_write(0,k);
}
if(rx_buf[3] == '4')
{
k =0.4;
x24c02_write(0,k);
}
if(rx_buf[3] == '5')
{
k =0.5;
x24c02_write(0,k);
}
if(rx_buf[3] == '6')
{
k =0.6;
x24c02_write(0,k);
}
if(rx_buf[3] == '7')
{
k =0.7;
x24c02_write(0,k);
}
if(rx_buf[3] == '8')
{
k =0.8;
x24c02_write(0,k);
}
if(rx_buf[3] == '9')
{
k =0.9;
x24c02_write(0,k);
}
发送部分,也就是定时播报的那部分:
sprintf((char *)str4,"%.2f+%.1f+%02d%02d%02d",getADC()*3.3/4096,k,T.Hours,T.Minutes,T.Seconds);
HAL_UART_Transmit(&huart1,str4,30,1000);
- 按键转换LED状态
直接上代码
void function_chage(void)
{
if(HAL_GPIO_ReadPin(FUNCTION_GPIO_Port,FUNCTION_Pin)==0)
{
HAL_Delay(100);//按键消抖,设置成100时防止按久了来回跳
if(HAL_GPIO_ReadPin(FUNCTION_GPIO_Port,FUNCTION_Pin)==0)
{
led = 1-led;
if(led == 1)
{
LCD_DisplayStringLine(Line5," LED:ON ");
}
if(led == 0)
{
LCD_DisplayStringLine(Line5," LED:OFF ");
}
}
}
}
- 按键设置时间
这部分是需要RTC的基础的,我自己也啃了挺久,但是水平不够,这部分代码讲不清楚,有问题的话可以在评论区留言。
void time_setting(void)
{
if(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==0)
HAL_Delay(20);
if(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==0)
{
int c = 0;
HAL_Delay(700);//防止按久了,来回跳
LCD_Clear(White);
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line1," SETTING ");
LCD_DisplayStringLine(Line3,(uint8_t *)str);
while(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==1)
{
if(HAL_GPIO_ReadPin(CHANGE_GPIO_Port,CHANGE_Pin) == 0)
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(CHANGE_GPIO_Port,CHANGE_Pin)==0)
{
HAL_Delay(500);
c = c+1;
if(c == 3)
{
c=0;
}
}
}
if(HAL_GPIO_ReadPin(ADD_TIME_GPIO_Port,ADD_TIME_Pin)==0)
{
HAL_Delay(100);
if(HAL_GPIO_ReadPin(ADD_TIME_GPIO_Port,ADD_TIME_Pin)==0)
{
RTC_TimeTypeDef tTime ;
if(c==0)
{
tTime.Seconds = T.Seconds+1;
T.Seconds++;
}
if(c==1)
{
tTime.Minutes = T.Minutes+1;
T.Minutes++;
}
if(c==2)
{
tTime.Hours = T.Hours+1;
T.Hours++;
}
tTime.Seconds = T.Seconds;
tTime.Minutes = T.Minutes;
tTime.Hours = T.Hours;
sprintf((char *)str, " T:%02d-%02d-%02d",T.Hours,T.Minutes,T.Seconds);
LCD_DisplayStringLine(Line3,(uint8_t *)str);
HAL_RTC_SetTime(&hrtc, &tTime, RTC_FORMAT_BIN);
m=0;n=0;o=0;
}
}
if(c == 0)
{
LCD_DisplayStringLine(Line4," **");
}
if(c==1)
{
LCD_DisplayStringLine(Line4," ** ");
}
if(c==2)
{
LCD_DisplayStringLine(Line4," ** ");
}
}
LCD_Clear(White);
if(led==1)
{
LCD_DisplayStringLine(Line5," LED:ON ");
}
if(led==0)
{
LCD_DisplayStringLine(Line5," LED:OFF ");
}
return;
}
}
- 主函数代码
把上面的代码整合在一起,在加一些代码就可以写入主函数,实现题目要求的功能。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_RTC_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
HAL_RTC_Init(&hrtc);
LCD_Init();
LCD_Clear(White);
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line1," V1: ");
LCD_DisplayStringLine(Line3," k: ");
LCD_DisplayStringLine(Line5," LED:ON ");
LCD_DisplayStringLine(Line7," T:23-59-55 ");
HAL_RTC_GetTime(&hrtc, &T, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &D, RTC_FORMAT_BIN);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LCD_SetTextColor(Black);
sprintf((char *)str3, " K:%.1f",k);
x24c02_write(0,k);//向E2PROM写入k的大小
LCD_DisplayStringLine(Line3,(uint8_t *)str3);
if(t==2) //每秒刷新一次时间
{
HAL_RTC_GetTime(&hrtc, &T, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &D, RTC_FORMAT_BIN);
sprintf((char *)str, " T:%02d-%02d-%02d",T.Hours,T.Minutes,T.Seconds);
LCD_DisplayStringLine(Line7,(uint8_t *)str);
t = 0; //将t侵凌
p = p+1; //p值每秒加1
}
function_chage(); //按键扫描判断是否打开LED的功能
time_setting(); //按键扫描判断是否进入时间设置
rx_k(); //串口中断接收K值的大小
if(T.Hours == 0x00)//当时间从23-59-55变为00-00-00时,开启ADC的显示
{
adc = 1;
}
if(adc == 1)
{
sprintf((char *)str2, " V1:%.2f",getADC()*3.3/4096);
LCD_DisplayStringLine(Line1,(uint8_t *)str2);
if((float)(getADC()*3.3/4096)>(float)(3.3*k) && led == 1)
{
LED_H(); //小灯灭
}
}
t = t+1;
HAL_Delay(250); //将500ms延时分为两次,这样做是为了让小灯闪烁起来
LED_L(); //小灯亮
HAL_Delay(249);
if(p==30) //每三十秒自动播报
{
sprintf((char *)str4,"%.2f+%.1f+%02d%02d%02d",getADC()*3.3/4096,k,T.Hours,T.Minutes,T.Seconds);
HAL_UART_Transmit(&huart1,str4,30,1000);
p = 0; //p值清零
}
}
/* USER CODE END 3 */
}
把工程下载到板子上,功能完好,该题就到这里结束啦。
4. 工程文件分享
最后分享一下工程文件,有需要的可以下载,有问题的欢迎随时在评论区留言。
链接: https://download.csdn.net/download/SUPPER__xxh/75305922.
文章评论