完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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芯片进行仿真 至此整个作业就全部完成啦!!!!! 嵌入式软硬结合,还是很有意思的,虽然项目很简单但是我还是从中收获了很多。 |
|
|
|
您好,我想问一下这个设计需要买一些什么元器件呢,新手小白不太懂,想按着这个自己去做一下
|
|
|
|
只有小组成员才能发言,加入小组>>
4375个成员聚集在这个小组
加入小组3295 浏览 0 评论
航顺(HK)联合电子发烧友推出“近距离体验高性能Cortex-M3,免费申请价值288元评估板
4237 浏览 1 评论
4248 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 18:05 , Processed in 0.932689 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号