使用最新版STM32G431系列,cubemx配置
1 题目分析
使用到的外设:LED、LCD、按键、TIM(pwm)、RTC。
这一届用到状态机,逻辑难度较高。
2 Cubemx配置
外设具体方法参考我写的其他文章
配置完成如下:
时钟树配置如下:
3 文件移植
其中灯和按键程序自己添加
添加到项目中
先编译,左边会显示出添加的文件
添加头文后再编译一下,确保头文件和.c文件都被正确引用
4 代码
所有的外设配置Cubemx都配置好了,无需自己配置(巨省工作量)
下面介绍自己添加的部分
4.1 led和Key部分
头文件 ledAndKey.h
#include "main.h"
void Led_Disp(unsigned char c);
unsigned char Key_Scan(void);
#include "ledAndKey.h"
//灯
void Led_Disp(unsigned char c)
{
//全部熄灭
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
//点亮对应位
HAL_GPIO_WritePin(GPIOC, c<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
//按键扫描
unsigned char Key_Scan(void)
{
unsigned char c;
c=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
{
c = 1;
}
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET)
{
c = 2;
}
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET)
{
c = 3;
}
else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
{
c = 4;
}
return c;
}
4.2 主函数部分
#include "main.h"
#include "rtc.h"
#include "tim.h"
#include "gpio.h"
#include "ledAndKey.h"
#include <stdio.h>
#include "lcd.h"
void SystemClock_Config(void);
void keyPro(void);
void lcdPro(void);
void ledPro(void);
void running(void);
void OpenDool(void);//开门
void CloseDool(void);//关门
void Up(void);//上升
void Dowm(void);//下降
void Stop(void);//所有电机停止
//dida
__IO uint32_t uwtick_Key,uwtick_Lcd,uwtick_Led,uwtick_Run,uwtick_Stage;
//key
unsigned char Key_Value,Key_Old,Key_Up,Key_Dowm;
unsigned char key_tim = 0; //0-按键封锁状态
//led
unsigned char Led_light;
unsigned char Led_flag;
//user
unsigned char platform = 1; //表示当前平台
unsigned char str[20];
unsigned char updowm = 0; //电机运行状态0停上1下2
unsigned char selected_platform = 0;//选中的楼层
unsigned char motor_runflag = 0;//电机运行状态 0完全停机 1运行 2待机等待
unsigned char Stage = 0; //状态机
RTC_DateTypeDef rtc_date;
RTC_TimeTypeDef rtc_time;
int main(void)
{
HAL_Init();
SystemClock_Config();
LCD_Init();
MX_GPIO_Init();
MX_TIM3_Init();
MX_TIM17_Init();
MX_RTC_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
while (1)
{
keyPro();
lcdPro();
ledPro();
running();
}
}
void lcdPro(void)
{
if(uwTick - uwtick_Lcd<50) return;
uwtick_Lcd = uwTick;
//时间处理
HAL_RTC_GetDate(&hrtc,&rtc_date,FORMAT_BIN);
HAL_RTC_GetTime(&hrtc,&rtc_time,FORMAT_BIN);
sprintf((char *)str," Now Platform");
LCD_DisplayStringLine(Line1,str);
sprintf((char *)str," %d ",platform);
LCD_DisplayStringLine(Line3,str);
sprintf((char *)str," %02d:%02d:%02d",rtc_time.Hours,rtc_time.Minutes,rtc_time.Seconds);
LCD_DisplayStringLine(Line5,str);
//辅助监视状态
if(updowm == 0)
sprintf((char *)str,"State:Stop ");
else if(updowm == 1)
sprintf((char *)str,"State:Up ");
else if(updowm == 2)
sprintf((char *)str,"State:Down ");
LCD_DisplayStringLine(Line6,str);
sprintf((char *)str,"Motor:%d",motor_runflag); //电机运行状态
LCD_DisplayStringLine(Line7,str);
sprintf((char *)str,"TEST");
LCD_DisplayStringLine(Line9,str);
}
//状态机实现
void running(void)
{
if(uwTick - uwtick_Run<50) return;
uwtick_Run = uwTick;
if(motor_runflag!=0) //电梯处于工作状态
{
switch(Stage)
{
case 0: //开始运行,电梯关门
uwtick_Stage = uwTick;//记录关门时间
motor_runflag = 1;
Stage = 1;
break;
case 1: //电梯关门中 4s
if(uwTick - uwtick_Stage<4000)
{//关门ing
CloseDool();
}
else
{
Stage = 2;
Stop();
}
break;
case 2: //判断升降,并开始计时
uwtick_Stage = uwTick;//记录升降开始时间
if(updowm == 0)
{
if(selected_platform>(1<<(platform-1))) //判断是否有比当前高的楼层选中
updowm = 1;//上
else
updowm = 2;//下
}
else if(updowm == 1) //上升时
{
if(selected_platform>(1<<(platform-1))) //判断是否有比当前高的楼层选中
updowm = 1;//上
else
updowm = 2;//下
}
else if(updowm == 2) //下降时
{
if(selected_platform<(1<<(platform-1))) //判断是否有比当前低的楼层选中
updowm = 2;//下
else
updowm = 1;//上
}
Stage = 3;
break;
case 3:
if(uwTick - uwtick_Stage<6000)
{
//电梯上下运行中
if(updowm == 1)
{
Up();
}
else if(updowm ==2)
{
Dowm();
}
}
else //到达新楼层
{
if(updowm == 1)//上
platform++;
else if(updowm == 2)//下
platform --;
if((1<<(platform-1))&selected_platform)//判断是否是选中楼层
{
selected_platform &= ~(1<<(platform-1));//清除选中楼层标记
Stop();
Stage = 4;
}
else//继续运行
{
uwtick_Stage = uwTick;
}
}
break;
case 4:
uwtick_Stage = uwTick;//电机开门计时
Stage = 5;
break;
case 5:
if(uwTick - uwtick_Stage<4000)
{
//电梯开门中
OpenDool();
}
else //判断停机还是等待
{
Stop();
if(selected_platform!=0) //还有楼层被选中
{
motor_runflag = 2; //电机待机
uwtick_Stage = uwTick;//等待2s开始计时,期间允许新的楼层选中
Stage = 6;
}
else //没有选中的楼层了,结束循环
{
Stage = 0;
motor_runflag = 0;//彻底停机
}
}
break;
case 6:
if(uwTick - uwtick_Stage<2000)
{
//等待中
sprintf((char *)str,"Wait.. ");
LCD_DisplayStringLine(Line8,str);
}
else
{
//进入下一次循环
Stage = 0;
}
break;
}
}
else
{
sprintf((char *)str,"Nothing ");
LCD_DisplayStringLine(Line8,str);
}
}
void keyPro(void)
{
if(uwTick - uwtick_Key<50) return;
uwtick_Key = uwTick;
Key_Value = Key_Scan();
Key_Dowm = Key_Value&(Key_Value^Key_Old);
Key_Up = ~Key_Value&(Key_Value^Key_Old);
Key_Old = Key_Value;
if(Key_Dowm!=0) //代表有按键按下
{
if(key_tim == 0&&motor_runflag == 0)
{
key_tim = 1;
}
}
if(key_tim !=0||motor_runflag == 2) //按键有效 电机完全停止 或者中途等待
{
if(Key_Dowm == 1&&(platform!=1))
{
selected_platform|=0x1;
}
else if(Key_Dowm == 2&&(platform!=2))
{
selected_platform|=0x2;
}
else if(Key_Dowm == 3&&(platform!=3))
{
selected_platform|=0x4;
}
else if(Key_Dowm == 4&&(platform!=4))
{
selected_platform|=0x8;
}
key_tim++;
if(key_tim>=20) //1s
{
key_tim = 0;
motor_runflag = 1;//电梯开始运行
}
else if(Key_Dowm!=0) //新按键按下时刷新时间
{
key_tim = 1;
}
}
}
void ledPro(void)
{
if(uwTick - uwtick_Led<200) return;
uwtick_Led = uwTick;
Led_light &= 0xf0;//低四位清0
Led_light|=selected_platform;
if(Led_flag) //流水灯
{
if(updowm == 1)//上
{
if((Led_light&0xF0) == 0) //高4位为0
{
Led_light|=0x80; //8位置1
}
else
{
Led_light = (Led_light&0x0f)+((Led_light>>1)&0xf0);
}
}
else if(updowm == 2)//下
{
if((Led_light&0xF0) == 0)
{
Led_light|=0x10; //5位置1
}
else
{
Led_light = (Led_light&0x0f)+((Led_light&0xf0)<<1);
}
}
}
else//高4位 清0
{
Led_light&=0x0f;
}
Led_Disp(Led_light);
}
void OpenDool(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,300);
sprintf((char *)str,"Opening dool ");
LCD_DisplayStringLine(Line8,str);
}
void CloseDool(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,250);
sprintf((char *)str,"Closeing dool ");
LCD_DisplayStringLine(Line8,str);
}
void Up(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,800);
sprintf((char *)str,"moveing UP ");
LCD_DisplayStringLine(Line8,str);
Led_flag = 1;
}
void Dowm(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,600);
sprintf((char *)str,"moveing Down ");
LCD_DisplayStringLine(Line8,str);
Led_flag = 1;
}
void Stop(void)
{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,0);
__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,0);
Led_flag = 0;
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}