历史上的今天
今天是:2025年02月04日(星期二)
2021年02月04日 | 【STM32G4】---实战—“电子定时器”
2021-02-04 来源:eefocus
前言
为了减少篇幅,各模块的初始化均在模块配置中,可以随时去翻看博客,还有function里面的函数,将不再罗列出来,只是截图展示。
一、题目
基本要求
1.1 使用 CT117E 嵌入式竞赛板,完成试题功能的程序设计与调试;
1.2 设计与调试过程中,可参考组委会提供的“资源数据包”;
1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil工程文件到服务器。
硬件框图
通过按键设置定时时间,启动定时器后,开始倒计时;计时过程中,可以暂停、取消定时器。在定时时间内,按要求输出 PWM 信号和控制 LED 指示灯。系统框图如图 1 所示:
功能描述
1、LCD 显示
LCD 显示存储位置、定时时间和当前状态。系统预留 5 个存储位置用于存储常用的定时时间。当定时器停止时,当前状态为 Standby;当系统正在设置时间时,当前状态为 Setting;当定时器运行时,当前状态为 Running,定时器暂停时,当前状态为 Pause。
2、按键功能
系统使用 4 个按键,B1、B2、B3 和 B4。
按键 B1 为存储位置切换键。每按一次,存储位置依次以 1、2、3、4、5循环切换,切换后定时时间设定为当前位置存储的时间。
按键 B2 为时间位置(时、分、秒)切换键和存储键。短按 B2 键进入时间设置状态。每次短按 B2 键,设置位置以时、分、秒循环切换,并突出显示(高亮)当前位置;设置完后,长按 B2 键(超过 0.8 秒)把设置的时间存储到当前的存储位置,并推出设置状态。如果是临时设置定时时间,则不需存储,直接按定时器启动按键。
按键 B3 为时、分、秒(按键 B2 确定当前位置)数字增加键。每短按B3 一次,数字递增一次;按住 B3 超过 0.8 秒,则数字快速递增,直到松开B3 按键。数字递增时,超出范围则从头循环。
按键 B4 为定时器启动键。短按 B4,定时器启动,开始运行;运行期间短按 B4,暂停定时器,再短按 B4,恢复定时器运行;长按 B4(超过 0.8 秒),则取消定时器运行,回到 Standby 状态。
3、PWM 输出和 LED 显示
定时器运行时,PA6 口输出 PWM 信号,同时 LED 灯(LD1)以 0.5 秒的频率闪烁。PWM 信号频率为 1KHz,占空比为 80%。
定时器停止或暂停时,停止输入 PWM 信号,LED 灯灭。
4、定时时间存储
设定好的定时时间存储在 EEPROM 中。
掉电重启后,显示存储位置 1 的定时时间。
二、模块初始化以及功能分析
1.模块的初始化
需要用的模块:LCD、IIC、四个按键、LED、TIM3(PA
6)
2.模块功能分析
LCD:显示-----》Display();
IIC:读取和存储信息到EEPROM-----》Write_Time();Read_Time();
按键:对参数进行调整-----》KEY_Handle();KEY_Scan();
LED:提示作用-----》LED();
TIM3:初始化
(本次赛题主要是考代码逻辑,特别是按键处理的方法。在模块方面用的比较少)
三、函数实现
1.void Display(void);
显示功能如下:
Location表示设置时间的地址,Location为4时,表示不设置时间。(单独点亮一个字符,方法如下,若有其他方法,欢迎评论)
mode表示定时器的四种状态:
0:Standby
1:Setting
2:Running
3:Pause
void Dispaly(void)
{
sprintf((char *)str," N0 %d",signal + 1);
LCD_DisplayStringLine(Line1, str);
if(Location == 4)//设置部分
{
LCD_ClearLine(Line4);
LCD_SetTextColor(Black);
sprintf((char *)str," %02d: %02d: %02d",Now_Time[0],Now_Time[1],Now_Time[2]);
LCD_DisplayStringLine(Line4, str);
}
else if(Location == 0)
{
LCD_SetTextColor(Black);
sprintf((char *)str," : %.2d: %.2d",Now_Time[1],Now_Time[2]);
LCD_DisplayStringLine(Line4, str);
LCD_SetTextColor(Red);
LCD_DisplayChar(Line4,210, Now_Time[0]/10 + 0x30);
LCD_DisplayChar(Line4,195, Now_Time[0]%10 + 0x30);
LCD_SetTextColor(Black);
}
else if(Location == 1)
{
LCD_SetTextColor(Black);
sprintf((char *)str," %.2d: : %.2d",Now_Time[0],Now_Time[2]);
LCD_DisplayStringLine(Line4, str);
LCD_SetTextColor(Red);
LCD_DisplayChar(Line4,150, Now_Time[1]/10 + 0x30);
LCD_DisplayChar(Line4,135, Now_Time[1]%10 + 0x30);
LCD_SetTextColor(Black);
}
else if(Location == 2)
{
LCD_SetTextColor(Black);
sprintf((char *)str," %.2d: %.2d: ",Now_Time[0],Now_Time[1]);
LCD_DisplayStringLine(Line4, str);
LCD_SetTextColor(Red);
LCD_DisplayChar(Line4,60, Now_Time[2]/10 + 0x30);
LCD_DisplayChar(Line4,45, Now_Time[2]%10 + 0x30);
LCD_SetTextColor(Black);
}
if(mode == 0)
LCD_DisplayStringLine(Line7, " Standby ");
else if(mode == 1)
LCD_DisplayStringLine(Line7, " Setting ");
else if(mode == 2)
LCD_DisplayStringLine(Line7, " Running ");
else if(mode == 3)
LCD_DisplayStringLine(Line7, " Pause ");
}
2.void Read_Time(void);void Write_Time(void);
void Write_Time(void)
{
IIC_Write(0x00,Hour[0]); HAL_Delay(10);
IIC_Write(0x01,Minute[0]);HAL_Delay(10);
IIC_Write(0x02,Second[0]);HAL_Delay(10);
IIC_Write(0x10,Hour[1]); HAL_Delay(10);
IIC_Write(0x11,Minute[1]);HAL_Delay(10);
IIC_Write(0x12,Second[1]);HAL_Delay(10);
IIC_Write(0x20,Hour[2]); HAL_Delay(10);
IIC_Write(0x21,Minute[2]);HAL_Delay(10);
IIC_Write(0x22,Second[2]);HAL_Delay(10);
IIC_Write(0x30,Hour[3]); HAL_Delay(10);
IIC_Write(0x31,Minute[3]);HAL_Delay(10);
IIC_Write(0x32,Second[3]);HAL_Delay(10);
IIC_Write(0x40,Hour[4]); HAL_Delay(10);
IIC_Write(0x41,Minute[4]);HAL_Delay(10);
IIC_Write(0x42,Second[4]);HAL_Delay(10);
}
void Read_Time(void)
{
Hour[0] = IIC_Read(0x00);HAL_Delay(10);
Minute[0] = IIC_Read(0x01);HAL_Delay(10);
Second[0] = IIC_Read(0x02);HAL_Delay(10);
Hour[1] = IIC_Read(0x10);HAL_Delay(10);
Minute[1] = IIC_Read(0x11);HAL_Delay(10);
Second[1] = IIC_Read(0x12);HAL_Delay(10);
Hour[2] = IIC_Read(0x20);HAL_Delay(10);
Minute[2] = IIC_Read(0x21);HAL_Delay(10);
Second[2] = IIC_Read(0x22);HAL_Delay(10);
Hour[3] = IIC_Read(0x30);HAL_Delay(10);
Minute[3] = IIC_Read(0x31);HAL_Delay(10);
Second[3] = IIC_Read(0x32);HAL_Delay(10);
Hour[4] = IIC_Read(0x40);HAL_Delay(10);
Minute[4] = IIC_Read(0x41);HAL_Delay(10);
Second[4] = IIC_Read(0x42);HAL_Delay(10);
}
3.uint8_t KEY_Scan(uint8_t mode);
由于本实验牵扯到长按(大于0.8s)和短按,并且长按是需要实时操作对应变量,所以长按的操作需要检测到马上执行。不能等按完了才执行。所以这里用0.2s的延时,次数加到4以后就进行长按操作。
变量声明:
Now_Time是当前显示的时间。
Time是存储的时间。
考虑到有暂时设定时间且不进行存储的情况,后面也引入了Aim_Time,定时结束的目标时间。
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t flag=1;
uint8_t count = 0;
if(mode) flag = 1;
if(flag &&(KEY_B1 == 0 || KEY_B2 == 0 || KEY_B3 == 0 || KEY_B4== 0 ))
{
HAL_Delay(10);
flag = 0;
if (KEY_B1 == 0) return B1_Press;
else if (KEY_B2 == 0)
{
while(KEY_B2 == 0){
HAL_Delay(200);
count++;//每0.2s加一
}
if(count <= 4) return B2_Press;
else return B2_Press_Long;
}
else if (KEY_B3 == 0)
{
while(KEY_B3 == 0){
Dispaly();
HAL_Delay(200);
count++;//每0.2s加一
if(count > 4)
{
Now_Time[Location] = Now_Time[Location]+1;
Now_Time[0] = Now_Time[0]%24;
Now_Time[1] = Now_Time[1]%60;
Now_Time[2] = Now_Time[2]%60;
Hour[signal]= Now_Time[0];
Minute[signal] = Now_Time[1];
Second[signal] = Now_Time[2];
}
}
if(count <= 4) return B3_Press;
}
else if (KEY_B4 == 0)
{
while(KEY_B4 == 0){
HAL_Delay(200);
count++;//每0.2s加一
}
if(count <= 4) return B4_Press;
else return B4_Press_Long;
}
}else if(KEY_B1 == KEY_B2 == KEY_B3 == KEY_B4 == 1) flag = 1;
return 0;
}
4.void KEY_Handle(uint8_t key);
按键 B1 为存储位置切换键。每按一次,存储位置依次以 1、2、3、4、5循环切换,切换后定时时间设定为当前位置存储的时间。(signal 变化)
按键 B2 为时间位置(时、分、秒)切换键和存储键。短按 B2 键进入时间设置状态。每次短按 B2 键,设置位置以时、分、秒循环切换,并突出显示(高亮)当前位置;设置完后,长按 B2 键(超过 0.8 秒)把设置的时间存储到当前的存储位置,并推出设置状态。如果是临时设置定时时间,则不需存储,直接按定时器启动按键。(Location变化)
按键 B3 为时、分、秒(按键 B2 确定当前位置)数字增加键。每短按B3 一次,数字递增一次;按住 B3 超过 0.8 秒,则数字快速递增,直到松开B3 按键。数字递增时,超出范围则从头循环。(Now_Time变化)
按键 B4 为定时器启动键。短按 B4,定时器启动,开始运行;运行期间短按 B4,暂停定时器,再短按 B4,恢复定时器运行;长按 B4(超过 0.8 秒),则取消定时器运行,回到 Standby 状态。(mode 变化)
void KEY_Handle(uint8_t Key)
{
if(Key == B1_Press)
{
Location = 4;
signal++;
signal = signal % 5;
Now_Time[0] = Hour[signal];
Now_Time[1] = Minute[signal];
Now_Time[2] = Second[signal];
}
else if(Key == B2_Press)
{
mode = 1;
if(Location == 4)
Location = 0;
else
{
Location++;
Location = Location % 3;
}
}
else if(Key == B2_Press_Long)
{
Location = 4;
mode = 0;
Hour[signal]= Now_Time[0];Minute[signal] = Now_Time[1];Second[signal] = Now_Time[2];
Write_Time();
}
else if(Key == B3_Press)
{
Now_Time[Location] = Now_Time[Location]+1;
Now_Time[0] = Now_Time[0]%24;
Now_Time[1] = Now_Time[1]%60;
Now_Time[2] = Now_Time[2]%60;
}
else if(Key == B4_Press)
{
if(mode == 1)
{
mode = 2;
HAL_TIM_Base_Start(&htim3);
Location = 4;
Aim_Time[signal] = Now_Time[0];
Aim_Time[signal] = Now_Time[1];
Aim_Time[signal] = Now_Time[2];
Now_Time[0] = Now_Time[1] = Now_Time[2] = 0;
}
else if(mode == 2) mode = 3;//暂停
else
{
Aim_Time[signal] = Hour[signal];
Aim_Time[signal] = Minute[signal];
Aim_Time[signal] = Second[signal];
mode = 2;
HAL_TIM_Base_Start(&htim3);
}
}
else if(Key == B4_Press_Long)
{
mode = 0;
}
}
5.void LED(void);void LED_OFF(void);
void LED(void);每进入一次LD1变换一次(TOGGLE函数似乎用不了,本人也不清楚)
void LED_OFF(void);关闭所有LED
void LED(void)
{
static uint16_t i;
i++;
if(i % 2)HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
}
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
|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);
}
void LED_OFF(void)
{
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);
}
6.void ADD(void);
时间加1函数
定时到目标时间的结束标志mode = 0;
void ADD(void)
{
Now_Time[2]++;
if(Now_Time[2] >= 60)
{
Now_Time[2] = 0;
Now_Time[1]++;
}
if(Now_Time[1] >= 60)
{
Now_Time[1] = 0;
Now_Time[0]++;
}
Now_Time[0] = Now_Time[0] % 24;
if(Now_Time[0] == Aim_Time[0] && Now_Time[1] ==Aim_Time[1] && Now_Time[2] == Aim_Time[2]) mode = 0;
}
7.int main(void);
初始化;

LCD_Init();
LCD_Clear(White);
LCD_SetTextColor(Black);
I2CInit();
IIC_Write(0x00,0);HAL_Delay(10);
IIC_Write(0x01,0);HAL_Delay(10);
IIC_Write(0x02,0);HAL_Delay(10);
IIC_Write(0x10,0);HAL_Delay(10);
IIC_Write(0x11,1);HAL_Delay(10);
IIC_Write(0x12,0);HAL_Delay(10);
IIC_Write(0x20,5);HAL_Delay(10);
IIC_Write(0x21,20);HAL_Delay(10);
IIC_Write(0x22,00);HAL_Delay(10);
IIC_Write(0x30,13);HAL_Delay(10);
IIC_Write(0x31,14);HAL_Delay(10);
IIC_Write(0x32,52);HAL_Delay(10);
IIC_Write(0x40,23);HAL_Delay(10);
IIC_Write(0x41,59);HAL_Delay(10);
IIC_Write(0x42,59);HAL_Delay(10);
LED_OFF();
HAL_Delay(100);
Read_Time();
HAL_Delay(1000);
while(1);

Dispaly();
key = KEY_Scan(0);
KEY_Handle(key);
if(mode == 2 && num == 1)
{
LED();
}
else if(mode != 2)
{
HAL_TIM_Base_Stop(&htim3);
LED_OFF();
}
if(nCount == 1 && mode == 2)
{
nCount = 0;
ADD();
}
8.void SysTick_Handler(void);
上面的num和nCount在哪变了,在哪计时呢?
就在滴答定时器里面咯。
大家打开stm32g4xx_it.c
if(mode == 2)
{
i++;j++;
}
if(i >= 1000)
{
nCount = 1;
i = 0;
}
if(j >= 500)
{
num = 1;
j = 0;
}
9.定时器输出PWM(Cubemx);
PWM未测试,有问题欢迎评论。

史海拾趣
|
2009年,全球由于盗版带来的损失大约为1.5万亿美元。盗版影响了所有商业市场,从Gucci手包到计算机芯片,直至专用算法等。全球供应链越来越复杂,对企业知识产权 (IP) 的剽窃也日益增多。全球供应链的安全和保护问题是保持竞争优势的关键,需要认真 ...… 查看全部问答> |
|
散分:顺便了解下:《Intel Xscale PXA270與Windows CE 嵌入式系統設計》这本书 请问各位: 谁了解这本书《Intel Xscale PXA270與Windows CE 嵌入式系統設計》 在网上看到这本书可挺贵 但是连目录都没有介绍的·… 查看全部问答> |
|
现在使用的是vxworks_rom这种映像,烧在flash里启动; 在符号表那块, 如果选择build-in的,其他命令可用,但在使用ld命令下载应用模块时报\"打不开相应的文件\"; 如果选择downloadable的,则可以使用ld顺利下载应用模块; ...… 查看全部问答> |
|
自己写的CPLD作为DSP外设读写数据的程序代码,请高手看看哪有问题 CPLD作为DSP外设时,DSP把数据放在IO空间,CPLD读取数据,根据相应的地址和信息控制外设工作的程序。自己编写了一段程序,但烧进CPLD后,DSP无法工作,请高手看看哪有问题 module project6(DATA,CLK,ADDLED,LED); input [7:0]DATA; & ...… 查看全部问答> |
|
我的大学生活即将结束;由于本人对软件比较感兴趣,毕业之后也许就远离的我的专业(电子信息科学与技术)了;我在大学期间也参加了电子设计竞赛等,在竞赛中我主要负责单片机程序的编写,所以对msp430系列的单片机比较熟悉;在这个系列的文章里,我主 ...… 查看全部问答> |
|
一个负责接收,三个发送,要是三个同时发送的时候,接收端的数据会不会变成乱码,比如第一个发送的数据是00 01,第二个发送的数据是02 03,第三个发送的数据是04 05,接收端的数据不会接收到就变成了00 02 04 01 03 05的?????????、… 查看全部问答> |
|
从申请到审核再到收到板子大概用了20多天时间,这20多天一直在思考应该如何设计这一套产品,现在终于拿到了,开始开箱测试。 板子图片在此就不拍了(手机太差,不好意思把拍的照片拿出来)。板子本身自带得有测试固件,所以拿到过后可以不用下载固 ...… 查看全部问答> |




