蓝桥杯嵌入式——基础模块的使用(初始化+调度器+LED+按键+LCD)
准备工作,创建工程
一、系统初始化
1.1 CubeMX配置
1.2 Keil配置
新建APP文件夹
1.3 Keil底层代码
#include "system.h"void System_Init(void)
{GPIOC->ODR &= 0x00ff;//清空PC8-PC15位 LED低电平亮此时全亮GPIOC->ODR |= 0xff00;//熄灭LEDGPIOD->BSRR = 0x01 << 2;//PD2置1GPIOD->BRR = 0x01 << 2;//PD2置0
}
二、系统调度器(scheduler.c)
2.1 CubeMX配置
调度器无需配置CubeMX。
2.2 Keil底层代码
typedef struct{void (*func)(void);uint32_t interval;//运行时间间隔uint32_t next_run;//下次运行时间
}task_t;
/*任务注册*/
task_t tasks[] = {{key_proc,10,0},{led_proc,10,0},{lcd_proc,100,0},{adc_proc,10,0},{uart_proc,10,0}
};
uint8_t task_count = sizeof(tasks)/sizeof(task_t);//任务数量void scheduler_run(void)
{//调度器运行for(uint8_t i = 0;i<task_count;i++){uint32_t current_time = HAL_GetTick();if(current_time >= tasks[i].next_run){tasks[i].next_run = current_time+tasks[i].interval;tasks[i].func();}}
}
三 、LED配置(led_app.c)
3.1 CubeMX配置
在第一节中已经配置了LED灯的PC8--PC15口以及 PD2的使能口,在此无需额外配置。
3.2 底层代码
#include "led_app.h"uint8_t ucled[8] = {0,1,0,1,1,0,0,0};
void led_show(uint8_t *ucled)
{uint8_t temp = 0x00;static uint8_t temp_old = 0xff;for(uint8_t i = 0;i<8;i++)temp |= (ucled[i] << i);//temp |= (ucled[i] << (7-i));//temp = 0101 1000//这里应该把7-去了,因为板子上是反的if(temp != temp_old){GPIOC->ODR &= 0x00ff;GPIOC->ODR |= ~(temp << 8);//~0101 1000 0000 0000 == 1010 0111GPIOD->BSRR |= (0x01 << 2);//PD2 0x04GPIOD->BRR |= (0x01 << 2);//0x04temp_old = temp;//}
}
void led_proc(void)
{led_show(ucled);
}
四、按键配置(key_app.c)
4.1 CubeMX配置
4.2 底层代码
#include "key_app.h"uint8_t key_value;
uint8_t key_old;
uint8_t key_down;
uint8_t key_up;uint8_t key_read(void)
{uint8_t temp = 0;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == GPIO_PIN_RESET)temp = 1;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == GPIO_PIN_RESET)temp = 2;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == GPIO_PIN_RESET)temp = 3;if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)temp = 4;return temp;
}
void key_proc(void)
{key_value = key_read();key_down = key_value & (key_old ^ key_value);key_up = ~key_value & (key_old ^ key_value);key_old = key_value;}
4.3 按键长按&按键双击
uint8_t long_flag;
uint16_t key_1s;
uint8_t mul_flag;
uint16_t mul_500ms;
void key_proc(void)
{key_value = key_read();key_down = key_value & (key_old ^ key_value);key_up = ~key_value & (key_old ^ key_value);key_old = key_value;if(key_down == 1)long_flag = 1;if(key_up == 1){if(long_flag == 1){//短按long_flag = 0;//按下标志清零key_1s = 0;//计数清零}if(long_flag == 2){//长按long_flag = 0;ucled[7] ^= 1;//切换led状态}}if(key_down == 2){switch(mul_flag){case 0://单击ucled[6] ^= 1;mul_flag = 1;break;case 1://双击ucled[5] ^= 1;mul_flag = 2;break;case 2://三击ucled[4] ^= 1;mul_flag = 3;break;}}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //中断回调1ms进一次
{//定时器回调函数 800*100/80 000 000=0.001sif(htim -> Instance == TIM6){if(long_flag == 1){if(++key_1s >= 1000){long_flag = 2;key_1s = 0;}}if(mul_flag != 0){//非零计时 超过500清零if(++mul_500ms >= 500){mul_500ms = 0;mul_flag = 0;//超过500状态回归}}}
}
五、LCD配置(lcd_app.c)
5.1 CubeMX配置
使用LCD需要将PC0——PC15都配置为GPIO_Output,此外还有PB5,8,9,PA8也需要配置。(但不配置似乎没啥影响)
5.2 底层代码
5.2.1 初始化语句
需要先将lcd的文件移入自己的项目文件夹
使用LCD需要初始化
将下面代码添加到while循环之前
LCD_Init();LCD_Clear(Black);//清除整个LCD屏幕LCD_SetTextColor(White);//文本色为 白色LCD_SetBackColor(Black);//背景色为 黑色
5.2.2 官方LCD函数
sprintf合成函数在stdio.h这个库文件中
#include "lcd_app.h"char lcd_buffer[128];
void lcd_proc(void)
{sprintf(lcd_buffer," LCD_APP Test");LCD_DisplayStringLine(Line0,(u8*)lcd_buffer);LCD_DrawCircle(100,50,30);
}
5.2.3 升级版
#include "lcd_app.h"void LcdSprintf(uint8_t Line,char *format,...)
{char String[21];//缓冲区用于存放格式化的字符串va_list arg;//参数列表用于存储可变参数va_start(arg,format);//初始化可变参数列表vsprintf(String,format,arg);//格式化字符串并存储在缓冲区中va_end(arg);//清理参数列表LCD_DisplayStringLine(Line,(u8*)String);
}
void lcd_proc(void)
{LcdSprintf(Line2," LCD APP TEST");
}