提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
蓝桥杯嵌入式赛道练习,只是记录自己的练习代码,如果有误,欢迎指出!!!
一、题目分析
这是我的第一个练习,所以看到题目有点懵,感觉不难,但是无从下手,所有在写完一些基础的程序后,参考了哔哩哔哩Up主蚂蚁工厂分析
二、代码
1.定义变量
extern Keys keys[4]; // 按键数组
uchar Led = 0;
RTC_TimeTypeDef T; // RTC时间
RTC_DateTypeDef D; // RTC日期
uint ral_time; // 当前时间
uint last_time; // 上一次的时间
int ral_floor; // 目前所在楼层
int Floor[3] = {0, 0, 0}; // 要运行的楼层数组
int Up[4] = {0, 0, 0, 0}; // 要上升运行的楼层数组
int down[4] = {0, 0, 0, 0}; // 要下降运行的楼层数组
int p_arrUp = 0, p_arrdown = 0, p_run = 0; // 指向数组的运行位置
char text[30]; // LCD打印
int class_state; // 运行的步骤
2.按键
Keys keys[4]={0,0,0};//按键函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//识别按键并消抖
{
if(htim->Instance==TIM4)//判断中断是不是定时器4,定时器设置时间是10ms
{
keys[0].key_ral=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);//更新按键电平
keys[1].key_ral=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
keys[2].key_ral=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
keys[3].key_ral=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch(keys[i].key_sta)//判断按键
{
case 0:
{
if(keys[i].key_ral==0)
{
keys[i].key_sta=1;
}
}break;
case 1:
{
if(keys[i].key_ral==0)
{
keys[i].key_sta=2;
keys[i].key_flag=1;
}
else
{
keys[i].key_sta=0;
}
}break;
case 2:
{
if(keys[i].key_ral==1)
{
keys[i].key_sta=0;
}
}break;
}
}
}
}
/// @brief 读按键
/// @param 空
void Read_key(void)
{
if (keys[0].key_flag == 1)
{
Led |= 1; // 写Led
if (keys[0].key_reapt++ == 0)
{
tianarr(1); // 把按键写入数组
}
GetSecd();
last_time = ral_time; // 更新时间
keys[0].key_flag = 0;
}
if (keys[1].key_flag == 1)
{
Led |= 0x02;
if (keys[1].key_reapt++ == 0)
{
tianarr(2);
}
GetSecd();
last_time = ral_time;
keys[1].key_flag = 0;
}
if (keys[2].key_flag == 1)
{
Led |= 0x04;
if (keys[2].key_reapt++ == 0)
{
tianarr(3);
}
GetSecd();
last_time = ral_time;
keys[2].key_flag = 0;
}
if (keys[3].key_flag == 1)
{
Led |= 0x08;
if (keys[3].key_reapt++ == 0)
{
tianarr(4);
}
GetSecd();
last_time = ral_time;
keys[3].key_flag = 0;
}
Led &= ~(1 << (ral_floor - 1));
LedDisp(~(Led)); // 写Led
}
3.处理数据
处理按键的数据,运行后数组的数据顺序为运行的楼层顺序
void tianarr(int x) // 填数列
{
if (x > ral_floor)
{
Up[p_arrUp++] = x;
maopao(Up);
}
else if (x < ral_floor)
{
down[p_arrdown++] = x;
maopao(Up);
}
}
void maopao(int *arr) // 排序
{
int temp, i, j;
for (i = 0; i < 3; i++)
{
for (j = 3; j > i; j--)
{
if (arr[j] > arr[j - 1])
{
temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
}
void arrCap(void) // 合并数列
{
int i, j = 0;
for (i = 0; i < 3; i++)
{
if (i < p_arrUp)
{
Floor[i] = Up[p_arrUp - i - 1];
Up[p_arrUp - i - 1] = 0;
}
else
{
Floor[i] = down[j];
down[j++] = 0;
}
}
for (i = 0; i < 3; i++)
{
keys[i].key_reapt = 0;
}
}
4.其他函数
void DispLcD(void) // Led显示
{
LCD_DisplayStringLine(Line7, (uint8_t *)text);
sprintf(text, " %2d:%2d:%2d", T.Hours, T.Minutes, T.Seconds);
LCD_DisplayStringLine(Line6, (uint8_t *)text);
sprintf(text, " %d", ral_floor);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
void GetSecd(void) // 得到时间
{
HAL_RTC_GetTime(&hrtc, &T, RTC_FORMAT_BIN); // 获取RTC
HAL_RTC_GetDate(&hrtc, &D, RTC_FORMAT_BIN);
ral_time = T.Hours * 3600 + T.Minutes * 60 + T.Seconds;
}
5.每一个状态
5.1状态0
case 0:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 1 && (Up[0] || down[0]))//当最后一次按键按键1s后并且有数据才会进入下一个阶段
{
class_state = 1;
last_time = ral_time;
arrCap();
}
else
{
Read_key();
}
}
break;
5.2状态1
case 1:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, 50); // 设置占空比50%
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 设置PA5低电平
HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1); // 开启PWM
class_state = 2;
GetSecd(); // 更新时间
last_time = ral_time;
}
break;
5.3状态2
case 2:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 4)
{
class_state = 3;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);//停止PWM
last_time = ral_time;
}
else
{
LedClose();
}
}
break;
5.4状态3
case 3:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
if (Floor[p_run] > ral_floor)//判断上升还是下降
{
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, 80);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}
else
{
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, 60);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
}
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
class_state = 4;
GetSecd(); // 更新时间
last_time = ral_time;
}
break;
5.5状态4
case 4:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 6)
{
class_state = 5;
Floor[p_run] > ral_floor ? ral_floor++ : ral_floor--;
last_time = ral_time;
}
else
{
if (Floor[p_run] > ral_floor)
{
LedUP();
}
else
{
LedDown();
}
}
}
break;
5.6状态5
case 5:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
if (Floor[p_run] == ral_floor)
{
Floor[p_run] = 0;
p_run++;//指向下一个运行楼层
class_state = 6;
HAL_TIM_PWM_Stop(&htim16, TIM_CHANNEL_1);
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, 60);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1);//PWM&按键操作
sprintf(text, " %d", ral_floor);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
HAL_Delay(300);
LCD_ClearLine(Line5);
HAL_Delay(300);
LCD_DisplayStringLine(Line5, (uint8_t *)text);//楼层闪烁
GetSecd(); // 更新时间
last_time = ral_time;
}
else
{
class_state = 4;
}
}
braek;
5.7状态6
case 6:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 4)
{
Led -= (1 << (ral_floor - 1));
LedDisp(~Led); // 灭灯
class_state = 7;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
last_time = ral_time;
}
else
{
LedOpen();
}
}
break;
5.8状态7
case 7:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (Floor[p_run] && p_run != 3)
{
class_state = 8;
last_time = ral_time;
}
else
{
class_state = 0;
p_arrdown = p_arrUp = p_run = 0;//全部数组指向0
}
}
break;
5.9状态8
case 8:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 2)
{
class_state = 1;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
last_time = ral_time;
}
}
break;
6主程序
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_TIM4_Init();
MX_TIM16_Init();
MX_TIM17_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
LedDisp(0x00);
LCD_Init(); // LCD屏的初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4); // 开启定时器时钟4
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1); // 开启PWM
HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1);
ral_floor = 1; // 默认楼层为1
GetSecd(); // 得到时间
last_time = ral_time; // 更新时间
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
DispLcD(); // 更新lcd;
switch (class_state)
{
case 0:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 1 && (Up[0] || down[0])) // 当最后一次按键按键1s后并且有数据才会进入下一个阶段
{
class_state = 1;
last_time = ral_time;
arrCap();
}
else
{
Read_key();
}
}
break;
case 1:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, 50); // 设置占空比50%
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 设置PA5低电平
HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1); // 开启PWM
class_state = 2;
GetSecd(); // 更新时间
last_time = ral_time;
}
break;
case 2:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 4)
{
class_state = 3;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);//停止PWM
last_time = ral_time;
}
else
{
LedClose();
}
}
break;
case 3:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
if (Floor[p_run] > ral_floor)//判断上升还是下降
{
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, 80);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}
else
{
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, 60);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
}
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
class_state = 4;
GetSecd(); // 更新时间
last_time = ral_time;
}
break;
case 4:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 6)
{
class_state = 5;
Floor[p_run] > ral_floor ? ral_floor++ : ral_floor--;
last_time = ral_time;
}
else
{
if (Floor[p_run] > ral_floor)
{
LedUP();
}
else
{
LedDown();
}
}
}
break;
case 5:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
if (Floor[p_run] == ral_floor)
{
Floor[p_run] = 0;
p_run++;//指向下一个运行楼层
class_state = 6;
HAL_TIM_PWM_Stop(&htim16, TIM_CHANNEL_1);
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, 60);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1);//PWM&按键操作
sprintf(text, " %d", ral_floor);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
HAL_Delay(300);
LCD_ClearLine(Line5);
HAL_Delay(300);
LCD_DisplayStringLine(Line5, (uint8_t *)text);//楼层闪烁
GetSecd(); // 更新时间
last_time = ral_time;
}
else
{
class_state = 4;
}
}
braek;
case 6:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 4)
{
Led -= (1 << (ral_floor - 1));
LedDisp(~Led); // 灭灯
class_state = 7;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
last_time = ral_time;
}
else
{
LedOpen();
}
}
break;
case 7:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (Floor[p_run] && p_run != 3)
{
class_state = 8;
last_time = ral_time;
}
else
{
class_state = 0;
p_arrdown = p_arrUp = p_run = 0;//全部数组指向0
}
}
break;
case 8:
{
sprintf(text, " %d", class_state);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
GetSecd(); // 更新时间
if (ral_time - last_time > 2)
{
class_state = 1;
HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);
last_time = ral_time;
}
}
break;
}
sprintf(text, " %d %d %d", Floor[0], Floor[1], Floor[2]);
LCD_DisplayStringLine(Line1, (uint8_t *)text);
}
/* USER CODE END 3 */
}
总结
本人新手,只学过江科大32标准库,HAL没有系统学过,如有错误欢迎大佬指出!文章的主要目的也是记录自己的学习过程。