STM32的简易电子表
前言:最近在做嵌入式选修课设,基于STM32F103C8Tx实现电子表的简单模拟。由于没有芯片,老师只是要求我们用Proteus进行仿真(Proteus仿真有点不准确),课程结束以后特地写一篇博客来记录自己的想法
首先我们需要设计原理图,原理图共有两部分,一部分是电源的设计,另一部分是数码管以及按键的电路设计
对于电源部分我们需要对VCC进行降压处理(STM32芯片正常工作电压为3.3V),这里用到了BUCK电路,有需要了解的可以点击了解BUCK电路
下面是数码管以及按键的原理图
2. 接下来我们可以利用Cube生成代码,时间的更新我们采用定时器中断即可
1.打开STM32CubeMX,新建项目选择STM32F103C8Tx
2.设置RCC时钟源
3.设置GPIO引脚
4.配置定时器,这里选择的是TIM3(有关定时器的知识读者可自行了解)
5.配置时钟树
6.生成代码并用keil打开
3. 编写代码
1.void SystemClock_Config(void)
void SystemClock_Config(void)
{
HAL_StatusTypeDef ret = HAL_OK;
RCC_OscInitTypeDef RCC_OscInitStructure;
RCC_ClkInitTypeDef RCC_ClkInitStructure;
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //时钟源为HSE
RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打开HSE
RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1; //HSE预分频
RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打开PLL
RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStructure.PLL.PLLMUL=RCC_PLL_MUL9; //主PLL倍频因子
ret=HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化
if(ret!=HAL_OK) while(1);
//选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; //AHB分频系数为1
RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; //APB1分频系数为2
RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; //APB2分频系数为1
ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2); //同时设置FLASH延时周期
if(ret!=HAL_OK) while(1);
}
2.void GPIO_INIT(void)
void void GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
GPIO_Initure.Pin=K4_Pin|K2_Pin; //K4_Pin|K2_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=K1_Pin; //K3_Pin|K1_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
GPIO_Initure.Pin=K3_Pin; //K3_Pin|K1_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin; //LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=F_Pin|A_Pin|P_Pin; //F_Pin|A_Pin|P_Pin;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
GPIO_Initure.Pin=KEY1_Pin|KEY0_Pin; //KEY1_Pin|KEY0_Pin;
GPIO_Initure.Mode=GPIO_MODE_INPUT; //input
GPIO_Initure.Speed=GPIO_SPEED_LOW; //低速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
HAL_GPIO_WritePin(GPIOA, K3_Pin|K4_Pin|K2_Pin|LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin, GPIO_PIN_SET); //置1
HAL_GPIO_WritePin(GPIOB, K1_Pin|F_Pin|A_Pin|P_Pin, GPIO_PIN_SET); //置1
}
3.void TIM3_Init(void)
void TIM3_Init(void)
{
TIM3_Handler.Instance=TIM3; //TIMER3
TIM3_Handler.Init.Prescaler=7200-1; //分频系数 500ms 500ms中断一次
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM3_Handler.Init.Period=5000-1; //自动装载值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频因子
HAL_TIM_Base_Init(&TIM3_Handler);
HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE
}
4.void HAL_TIM_Base_MspInit(TIM_HandleTypeDef htim)
//设置中断优先级
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim-》Instance==TIM3)
{
__HAL_RCC_TIM1_CLK_ENABLE(); //使能TIM1时钟
__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟
HAL_NVIC_SetPriority(TIM3_IRQn,1,3); //设置中断优先级
HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启ITM3中断
}
}
5.void TIM3_IRQHandler(void)
//TIMER3中断服务函数
void TIM3_IRQHandler(void)
{
//HAL_GPIO_TogglePin(A_GPIO_Port, A_Pin);
//HAL_GPIO_TogglePin(B_GPIO_Port, B_Pin);
//HAL_GPIO_TogglePin(C_GPIO_Port, C_Pin);
//HAL_GPIO_TogglePin(D_GPIO_Port, D_Pin);
//HAL_GPIO_TogglePin(E_GPIO_Port, E_Pin);
//HAL_GPIO_TogglePin(F_GPIO_Port, F_Pin);
//HAL_GPIO_TogglePin(G_GPIO_Port, G_Pin);
//HAL_GPIO_TogglePin(P_GPIO_Port, P_Pin);
//HAL_GPIO_TogglePin(LIGHTS_GPIO_Port, LIGHTS_Pin);
//Timer500ms();
TimerOneSecond();
//HAL_GPIO_TogglePin(LIGHTS_GPIO_Port, LIGHTS_Pin);
//delay_ms(10);
HAL_TIM_IRQHandler(&TIM3_Handler);
}
*6.void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef htim)
//回调函数,定时器中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==(&TIM3_Handler))
{
//HAL_GPIO_TogglePin(A_GPIO_Port, A_Pin);
//HAL_GPIO_TogglePin(B_GPIO_Port, B_Pin);
}
}
PS:这些都是基本的初始化函数也就是我们在Cube中配置的,我们需要的是设置定时器向上溢出的时间,并在定时器中断时对时间进行更新
下面我们编写显示函数
依次显示数码管的每个数字,利用视觉欺骗效果,人眼是观察不出来的,弊端就是仿真时会因电脑性能的原因而发生闪烁,实际上人眼是识别不出来的
uint8_t SEG[10]={0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe4, 0xfe, 0xf6};
int DELAY_TIME[4]={10, 10, 10, 10};
//选择点亮的数码管并将对应GPIO管脚置1
static void setSegOn(int index)
{
//GPIO PORT RESET
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K3_GPIO_Port, K3_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K4_GPIO_Port, K4_Pin, GPIO_PIN_RESET);
//GPIO PORT SET
switch(index)
{
case 0:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
break;
case 1:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_WritePin(K3_GPIO_Port, K3_Pin, GPIO_PIN_SET);
break;
case 3:
HAL_GPIO_WritePin(K4_GPIO_Port, K4_Pin, GPIO_PIN_SET);
break;
default:
Error_Handler();
break;
}
}
//通过对不同管脚的置位来显示对应的数字
static void DisplaySeg(uint8_t SegCode)
{
uint8_t value;
//P
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(P_GPIO_Port, P_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(P_GPIO_Port, P_Pin, GPIO_PIN_SET);
}
//G
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(G_GPIO_Port, G_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(G_GPIO_Port, G_Pin, GPIO_PIN_SET);
}
//F
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(F_GPIO_Port, F_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(F_GPIO_Port, F_Pin, GPIO_PIN_SET);
}
//E
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(E_GPIO_Port, E_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(E_GPIO_Port, E_Pin, GPIO_PIN_SET);
}
//D
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(D_GPIO_Port, D_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(D_GPIO_Port, D_Pin, GPIO_PIN_SET);
}
//C
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, GPIO_PIN_SET);
}
//B
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, GPIO_PIN_SET);
}
//A
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, GPIO_PIN_SET);
}
}
static void DisplayValue(uint8_t value)
{
DisplaySeg(SEG[value]);
}
//显示时间
void Display(void)
{
//第一个数字HOUR的十位
uint8_t Temp;
Temp = Time_Buf.Hour / 10;
setSegOn(0);
DisplayValue(Temp);
delay_ms(1400);
//第二个数字HOUR的个位
Temp = Time_Buf.Hour % 10;
setSegOn(1);
DisplayValue(Temp);
delay_ms(1400);
//第三个数字MINUTE的十位
Temp = Time_Buf.Min / 10;
setSegOn(2);
DisplayValue(Temp);
delay_ms(1400);
//第四个数字MINUTE的个位
Temp = Time_Buf.Min % 10;
setSegOn(3);
DisplayValue(Temp);
delay_ms(1400);
//点亮秒灯
if(Time_Buf.Ms)
{
HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_RESET);
//delay_ms(10);
//HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_SET);
}
}
//初始化TIME
void Init(void)
{
Time_Buf.Hour = 0;
Time_Buf.Min = 0;
Time_Buf.Sec = 0;
Time_Buf.Ms = 0;
}
针对按键事件,只需要扫描有无按键按下而后执行响应的操作
int GLIMMER_TIME = 500;
int COUNT = -1;
int END = 1;
int temp;
//判断按键是否被按下
void IsEdit(void)
{
if(!HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin))
{
//检查按钮是否未松开
while(!HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)){
delay_ms(10);
}
COUNT = (COUNT + 1) % 4;
END = 0;
}
}
//按键被按下执行相应的改变
void Edit(void)
{
// check whether edit button is push
if(!HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) && END == 0)
{
//检查按钮是否未松开
while(!HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)){
delay_ms(10);
}
//change the corresponding time
if(COUNT == 0)
{
Time_Buf.Hour = ( (((Time_Buf.Hour / 10) + 1) % 3) * 10 + Time_Buf.Hour % 10) % 24;
}
else if(COUNT == 1)
{
Time_Buf.Hour = ((Time_Buf.Hour / 10) * 10 + ((Time_Buf.Hour % 10) + 1) % 10) % 24;
}
else if(COUNT == 2)
{
Time_Buf.Min = (((Time_Buf.Min / 10 + 1) % 6) * 10 + Time_Buf.Min % 10) % 60;
}
else
{
Time_Buf.Min = (((Time_Buf.Min % 10 + 1) % 10) + Time_Buf.Min / 10 * 10 ) % 60;
}
}
}
定时器中断时的时间更新
//每500ms在定时器中断里执行一次时间的改变
void Timer500ms(void)
{
Time_Buf.Ms = (Time_Buf.Ms + 1) % 2;
Time_Buf.Sec += Time_Buf.Ms;
if(Time_Buf.Sec 》= 60)
{
Time_Buf.Sec = 0;
Time_Buf.Min += 1;
if(Time_Buf.Min 》= 60)
{
Time_Buf.Min = 0;
Time_Buf.Hour = (Time_Buf.Hour + 1) % 24;
}
}
}
Main()
Time_Def Time_Buf;
int main(void)
{
HAL_Init();
Init();
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(); //设置时钟,72M
LED_Init(); //初始化LED
TIM3_Init(); //定时器3初始化
while (1)
{
IsEdit();
Edit();
Display();
}
}
4.下面使用Proteus进行仿真
需要下载至少8.6版本的Proteus,低版本不能对STM32芯片进行仿真
至此整个作业就全部完成啦!!!!!
嵌入式软硬结合,还是很有意思的,虽然项目很简单但是我还是从中收获了很多。
STM32的简易电子表
前言:最近在做嵌入式选修课设,基于STM32F103C8Tx实现电子表的简单模拟。由于没有芯片,老师只是要求我们用Proteus进行仿真(Proteus仿真有点不准确),课程结束以后特地写一篇博客来记录自己的想法
首先我们需要设计原理图,原理图共有两部分,一部分是电源的设计,另一部分是数码管以及按键的电路设计
对于电源部分我们需要对VCC进行降压处理(STM32芯片正常工作电压为3.3V),这里用到了BUCK电路,有需要了解的可以点击了解BUCK电路
下面是数码管以及按键的原理图
2. 接下来我们可以利用Cube生成代码,时间的更新我们采用定时器中断即可
1.打开STM32CubeMX,新建项目选择STM32F103C8Tx
2.设置RCC时钟源
3.设置GPIO引脚
4.配置定时器,这里选择的是TIM3(有关定时器的知识读者可自行了解)
5.配置时钟树
6.生成代码并用keil打开
3. 编写代码
1.void SystemClock_Config(void)
void SystemClock_Config(void)
{
HAL_StatusTypeDef ret = HAL_OK;
RCC_OscInitTypeDef RCC_OscInitStructure;
RCC_ClkInitTypeDef RCC_ClkInitStructure;
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //时钟源为HSE
RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打开HSE
RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1; //HSE预分频
RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打开PLL
RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStructure.PLL.PLLMUL=RCC_PLL_MUL9; //主PLL倍频因子
ret=HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化
if(ret!=HAL_OK) while(1);
//选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; //AHB分频系数为1
RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; //APB1分频系数为2
RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; //APB2分频系数为1
ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2); //同时设置FLASH延时周期
if(ret!=HAL_OK) while(1);
}
2.void GPIO_INIT(void)
void void GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
GPIO_Initure.Pin=K4_Pin|K2_Pin; //K4_Pin|K2_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=K1_Pin; //K3_Pin|K1_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
GPIO_Initure.Pin=K3_Pin; //K3_Pin|K1_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin; //LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=F_Pin|A_Pin|P_Pin; //F_Pin|A_Pin|P_Pin;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
GPIO_Initure.Pin=KEY1_Pin|KEY0_Pin; //KEY1_Pin|KEY0_Pin;
GPIO_Initure.Mode=GPIO_MODE_INPUT; //input
GPIO_Initure.Speed=GPIO_SPEED_LOW; //低速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
HAL_GPIO_WritePin(GPIOA, K3_Pin|K4_Pin|K2_Pin|LIGHTS_Pin|G_Pin|B_Pin|C_Pin |E_Pin|D_Pin, GPIO_PIN_SET); //置1
HAL_GPIO_WritePin(GPIOB, K1_Pin|F_Pin|A_Pin|P_Pin, GPIO_PIN_SET); //置1
}
3.void TIM3_Init(void)
void TIM3_Init(void)
{
TIM3_Handler.Instance=TIM3; //TIMER3
TIM3_Handler.Init.Prescaler=7200-1; //分频系数 500ms 500ms中断一次
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM3_Handler.Init.Period=5000-1; //自动装载值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频因子
HAL_TIM_Base_Init(&TIM3_Handler);
HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE
}
4.void HAL_TIM_Base_MspInit(TIM_HandleTypeDef htim)
//设置中断优先级
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim-》Instance==TIM3)
{
__HAL_RCC_TIM1_CLK_ENABLE(); //使能TIM1时钟
__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟
HAL_NVIC_SetPriority(TIM3_IRQn,1,3); //设置中断优先级
HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启ITM3中断
}
}
5.void TIM3_IRQHandler(void)
//TIMER3中断服务函数
void TIM3_IRQHandler(void)
{
//HAL_GPIO_TogglePin(A_GPIO_Port, A_Pin);
//HAL_GPIO_TogglePin(B_GPIO_Port, B_Pin);
//HAL_GPIO_TogglePin(C_GPIO_Port, C_Pin);
//HAL_GPIO_TogglePin(D_GPIO_Port, D_Pin);
//HAL_GPIO_TogglePin(E_GPIO_Port, E_Pin);
//HAL_GPIO_TogglePin(F_GPIO_Port, F_Pin);
//HAL_GPIO_TogglePin(G_GPIO_Port, G_Pin);
//HAL_GPIO_TogglePin(P_GPIO_Port, P_Pin);
//HAL_GPIO_TogglePin(LIGHTS_GPIO_Port, LIGHTS_Pin);
//Timer500ms();
TimerOneSecond();
//HAL_GPIO_TogglePin(LIGHTS_GPIO_Port, LIGHTS_Pin);
//delay_ms(10);
HAL_TIM_IRQHandler(&TIM3_Handler);
}
*6.void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef htim)
//回调函数,定时器中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==(&TIM3_Handler))
{
//HAL_GPIO_TogglePin(A_GPIO_Port, A_Pin);
//HAL_GPIO_TogglePin(B_GPIO_Port, B_Pin);
}
}
PS:这些都是基本的初始化函数也就是我们在Cube中配置的,我们需要的是设置定时器向上溢出的时间,并在定时器中断时对时间进行更新
下面我们编写显示函数
依次显示数码管的每个数字,利用视觉欺骗效果,人眼是观察不出来的,弊端就是仿真时会因电脑性能的原因而发生闪烁,实际上人眼是识别不出来的
uint8_t SEG[10]={0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe4, 0xfe, 0xf6};
int DELAY_TIME[4]={10, 10, 10, 10};
//选择点亮的数码管并将对应GPIO管脚置1
static void setSegOn(int index)
{
//GPIO PORT RESET
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K3_GPIO_Port, K3_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(K4_GPIO_Port, K4_Pin, GPIO_PIN_RESET);
//GPIO PORT SET
switch(index)
{
case 0:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
break;
case 1:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_WritePin(K3_GPIO_Port, K3_Pin, GPIO_PIN_SET);
break;
case 3:
HAL_GPIO_WritePin(K4_GPIO_Port, K4_Pin, GPIO_PIN_SET);
break;
default:
Error_Handler();
break;
}
}
//通过对不同管脚的置位来显示对应的数字
static void DisplaySeg(uint8_t SegCode)
{
uint8_t value;
//P
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(P_GPIO_Port, P_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(P_GPIO_Port, P_Pin, GPIO_PIN_SET);
}
//G
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(G_GPIO_Port, G_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(G_GPIO_Port, G_Pin, GPIO_PIN_SET);
}
//F
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(F_GPIO_Port, F_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(F_GPIO_Port, F_Pin, GPIO_PIN_SET);
}
//E
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(E_GPIO_Port, E_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(E_GPIO_Port, E_Pin, GPIO_PIN_SET);
}
//D
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(D_GPIO_Port, D_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(D_GPIO_Port, D_Pin, GPIO_PIN_SET);
}
//C
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(C_GPIO_Port, C_Pin, GPIO_PIN_SET);
}
//B
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(B_GPIO_Port, B_Pin, GPIO_PIN_SET);
}
//A
SegCode = SegCode》》1;
value = SegCode&0x01;
if(value)
{
HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(A_GPIO_Port, A_Pin, GPIO_PIN_SET);
}
}
static void DisplayValue(uint8_t value)
{
DisplaySeg(SEG[value]);
}
//显示时间
void Display(void)
{
//第一个数字HOUR的十位
uint8_t Temp;
Temp = Time_Buf.Hour / 10;
setSegOn(0);
DisplayValue(Temp);
delay_ms(1400);
//第二个数字HOUR的个位
Temp = Time_Buf.Hour % 10;
setSegOn(1);
DisplayValue(Temp);
delay_ms(1400);
//第三个数字MINUTE的十位
Temp = Time_Buf.Min / 10;
setSegOn(2);
DisplayValue(Temp);
delay_ms(1400);
//第四个数字MINUTE的个位
Temp = Time_Buf.Min % 10;
setSegOn(3);
DisplayValue(Temp);
delay_ms(1400);
//点亮秒灯
if(Time_Buf.Ms)
{
HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_RESET);
//delay_ms(10);
//HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LIGHTS_GPIO_Port, LIGHTS_Pin, GPIO_PIN_SET);
}
}
//初始化TIME
void Init(void)
{
Time_Buf.Hour = 0;
Time_Buf.Min = 0;
Time_Buf.Sec = 0;
Time_Buf.Ms = 0;
}
针对按键事件,只需要扫描有无按键按下而后执行响应的操作
int GLIMMER_TIME = 500;
int COUNT = -1;
int END = 1;
int temp;
//判断按键是否被按下
void IsEdit(void)
{
if(!HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin))
{
//检查按钮是否未松开
while(!HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)){
delay_ms(10);
}
COUNT = (COUNT + 1) % 4;
END = 0;
}
}
//按键被按下执行相应的改变
void Edit(void)
{
// check whether edit button is push
if(!HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) && END == 0)
{
//检查按钮是否未松开
while(!HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)){
delay_ms(10);
}
//change the corresponding time
if(COUNT == 0)
{
Time_Buf.Hour = ( (((Time_Buf.Hour / 10) + 1) % 3) * 10 + Time_Buf.Hour % 10) % 24;
}
else if(COUNT == 1)
{
Time_Buf.Hour = ((Time_Buf.Hour / 10) * 10 + ((Time_Buf.Hour % 10) + 1) % 10) % 24;
}
else if(COUNT == 2)
{
Time_Buf.Min = (((Time_Buf.Min / 10 + 1) % 6) * 10 + Time_Buf.Min % 10) % 60;
}
else
{
Time_Buf.Min = (((Time_Buf.Min % 10 + 1) % 10) + Time_Buf.Min / 10 * 10 ) % 60;
}
}
}
定时器中断时的时间更新
//每500ms在定时器中断里执行一次时间的改变
void Timer500ms(void)
{
Time_Buf.Ms = (Time_Buf.Ms + 1) % 2;
Time_Buf.Sec += Time_Buf.Ms;
if(Time_Buf.Sec 》= 60)
{
Time_Buf.Sec = 0;
Time_Buf.Min += 1;
if(Time_Buf.Min 》= 60)
{
Time_Buf.Min = 0;
Time_Buf.Hour = (Time_Buf.Hour + 1) % 24;
}
}
}
Main()
Time_Def Time_Buf;
int main(void)
{
HAL_Init();
Init();
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(); //设置时钟,72M
LED_Init(); //初始化LED
TIM3_Init(); //定时器3初始化
while (1)
{
IsEdit();
Edit();
Display();
}
}
4.下面使用Proteus进行仿真
需要下载至少8.6版本的Proteus,低版本不能对STM32芯片进行仿真
至此整个作业就全部完成啦!!!!!
嵌入式软硬结合,还是很有意思的,虽然项目很简单但是我还是从中收获了很多。
举报