历史上的今天
返回首页

历史上的今天

今天是: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未测试,有问题欢迎评论。
在这里插入图片描述
在这里插入图片描述

推荐阅读

史海拾趣

FerriShield公司的发展小趣事

随着技术的成熟和市场的认可,FerriShield开始拓展产品线。公司研发团队不断改进和优化原始的铁磁屏蔽材料,并推出了针对不同应用场景的系列产品。例如,针对智能手机和平板电脑的轻薄型电磁屏蔽膜,以及针对大型数据中心的高效电磁屏蔽板。这些新产品的推出,使得FerriShield的市场份额逐步扩大。

Ferroperm公司的发展小趣事

随着全球环保意识的不断提高,Ferroperm公司也积极响应环保号召,致力于可持续发展。他们采用环保材料和生产工艺,减少生产过程中的污染和废弃物排放。同时,Ferroperm还积极参与环保公益活动,推动环保理念的普及和传播。这种对环保的关注和投入不仅体现了公司的社会责任感,也为公司的长远发展奠定了坚实的基础。

Cretex Companies Inc公司的发展小趣事

为了降低成本、提高生产效率,Cretex开始对产业链进行整合与优化。他们与上游供应商建立长期稳定的合作关系,确保原材料的稳定供应和质量可靠。同时,公司还加强了对下游客户的服务与支持,通过提供个性化的解决方案和优质的售后服务,增强了客户黏性。这些举措使得Cretex在激烈的市场竞争中保持了领先地位。

ALCOA公司的发展小趣事

随着技术的不断进步和市场的扩大,ALCOA公司的业务逐渐扩展到铝土矿开采、氧化铝精炼和原铝生产等领域。这种垂直整合的模式使得公司能够更好地控制原材料的质量和供应,提高了生产效率,也降低了成本。到了20世纪中期,ALCOA已经成为全球最大的铝业公司之一,几乎垄断了全球的铝市场。

Greenwich Instruments Ltd公司的发展小趣事

Greenconn Corp自创立之初便致力于连接器技术的研发与创新。在20世纪末,随着电子产品的普及和通讯技术的飞速发展,连接器作为电子设备间的桥梁,其重要性日益凸显。Greenconn Corp凭借其敏锐的市场洞察力和强大的研发实力,成功研发出了一系列高性能、高可靠性的连接器产品,迅速在汽车电子、通信设备等领域占据了一席之地。这些创新产品不仅满足了市场对连接器高质量、高效率的需求,还推动了整个电子行业的发展。

AMICC [AMIC TECHNOLOGY]公司的发展小趣事

近年来,电子行业面临着技术升级、市场变革等多重挑战。AMICC积极应对这些挑战,不断调整战略和业务模式。公司加大了对新兴技术的研发投入,加快了产品更新换代的速度。同时,AMICC还加强了与产业链上下游企业的合作,共同应对市场变化。这些措施使AMICC在行业中保持了领先地位,实现了持续稳健的发展。

问答坊 | AI 解惑

Altera白皮书-保护 FPGA 设计不受常见的入侵威胁

2009年,全球由于盗版带来的损失大约为1.5万亿美元。盗版影响了所有商业市场,从Gucci手包到计算机芯片,直至专用算法等。全球供应链越来越复杂,对企业知识产权 (IP) 的剽窃也日益增多。全球供应链的安全和保护问题是保持竞争优势的关键,需要认真 ...…

查看全部问答>

散分:顺便了解下:《Intel Xscale PXA270與Windows CE 嵌入式系統設計》这本书

请问各位:    谁了解这本书《Intel Xscale PXA270與Windows CE 嵌入式系統設計》 在网上看到这本书可挺贵 但是连目录都没有介绍的·…

查看全部问答>

关于Target Shell的问题,急!

现在使用的是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程序库<一>综述

我的大学生活即将结束;由于本人对软件比较感兴趣,毕业之后也许就远离的我的专业(电子信息科学与技术)了;我在大学期间也参加了电子设计竞赛等,在竞赛中我主要负责单片机程序的编写,所以对msp430系列的单片机比较熟悉;在这个系列的文章里,我主 ...…

查看全部问答>

晒WEBENCH设计的过程+FPGA 电源

FPGA 电源的负载设计 呵呵…

查看全部问答>

在读研究生想退学

我是一个文科学校读工科的研究生,现在很是纠结要不要退学。我感觉在这里就是浪费时间。导师没有项目,这一年我都是自己学习。感觉导师的工作就是给你改论文格式的。学校资源很差。退学念头已经有了大半年了。目前还在纠结当中。前一阵子我受不了这 ...…

查看全部问答>

无线接收数据的问题,一个接收,三个发送

一个负责接收,三个发送,要是三个同时发送的时候,接收端的数据会不会变成乱码,比如第一个发送的数据是00 01,第二个发送的数据是02 03,第三个发送的数据是04 05,接收端的数据不会接收到就变成了00 02 04 01 03 05的?????????、…

查看全部问答>

SensorTile 开箱上手

从申请到审核再到收到板子大概用了20多天时间,这20多天一直在思考应该如何设计这一套产品,现在终于拿到了,开始开箱测试。 板子图片在此就不拍了(手机太差,不好意思把拍的照片拿出来)。板子本身自带得有测试固件,所以拿到过后可以不用下载固 ...…

查看全部问答>