基于stm32的多功能时钟1——时钟显示
读者们,大家好!接着上一章多功能时钟(绪论)的内容,在这一章中,我将介绍多功能时钟的时钟显示部分。话不多说,我们正式开始吧~
多功能时钟,时钟显示功能是必不可少的。所以,我们利用stm32的定时器来计时。本来打算采用stm32的RTC实时时钟,但后来想,刚开始弄得时候,尽量简单一些,别一开始就给自己出难题,毕竟RTC实时时钟要配置的东西还挺多的。如果此次做得不错的话,后面可以再加RTC实时时钟。
stm32不同于51,共有11个定时器,其中2个高级控制定时器(TIM1和TIM8),4个普通定时器(TIM2~TIM5)和2个基本定时器(TIM6和TIM7),以及2个看门狗定时器和1个系统滴答定时器。这里,我们采用普通定时器TIM2,并且开启定时器的中断,中断时间为1s,并且在中断函数里,模拟时钟的计时功能。
(1)配置嵌套中断控制器NVIC
void tim2_nvic_config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级为2
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//子优先级为0
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
这里,我们只需对NVIC_InitStruct结构体的每个元素赋值,其中TIM2_IRQn为定时器TIM2中断线,设置优先级组为2,即抢占优先级组为4组,这里抢占优先级为2,子优先级为0,然后使能NVIC(优先级不能理解上网查询)。
(2)定时器初始化配置
void tim2_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
tim2_nvic_config(); //配置NVIC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启时钟
TIM_DeInit(TIM2); //定时器2复位
TIM_TimeBaseInitStruct.TIM_Period = 2000-1; //自动重装载寄存器值
TIM_TimeBaseInitStruct.TIM_Prescaler = 36000-1; //时钟预分频数
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); //初始化TIM2
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除溢出中断标志
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE); //使能时钟
}
TIM2初始化,首先配置NVIC,打开TIM2时钟,复位TIM2。然后对TIM_TimeBaseInitStruct结构体的每个元素赋值。这里,主要阐述如何计算定时中断时间。定时器的溢出中断时间由TIM_Period和TIM_Prescaler来决定的。这里,我直接给出公式:发生中断时间=(TIM_Period+1)*(TIM_Prescaler+1)/FCLK,而FCLK为72M,所以定时1s,可以这样:TIM_Period=2000-1,TIM_Prescaler=36000-1;最后清除溢出中断标志,使能时钟即可计时。
(3)编写中断计时函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2 ,TIM_IT_Update)!=RESET)
{
sec++;
if(sec>=60)
{
sec = 0;
min++;
if(min>=60)
{
min = 0;
hour++;
if(hour>=24)
{
hour = 0;
}
}
}
}
TIM_ClearITPendingBit(TIM2 ,TIM_FLAG_Update);
}
这里,先定义时、分、秒三个变量,然后在中断函数里,对时间变量的关系进行换算即可。
(4)编写时钟显示函数
这里,我们采用LCD12864实时显示。LCD12864的相关内容,我后面在LCD库函数章节中,会专门介绍的。这里,只将时间显示即可。
lcd_display_num_m(2, 16, hour/10);
lcd_display_num_m(2, 24, hour%10);
lcd_display_string(2,32,"时");
lcd_display_num_m(2, 48, min/10);
lcd_display_num_m(2, 56, min%10);
lcd_display_string(2,64,"分");
lcd_display_num_m(2, 80, sec/10);
lcd_display_num_m(2, 88, sec%10);
lcd_display_string(2,96,"秒");
LCD12864的驱动函数,我跟着黄老师的视频后面写的,在老师的基础上,增加了汉字字符串显示函数。这里,看成库函数即可,只需简单的调用,显示时间就行。
(5)按键调整时间
成功显示时间后,我们需要按键来调整时间。 我们需要设置时钟启/停键(K1),时间位选择键(K2),数值增加键(K3),数值减小键(K4)。
1.我们先对按键的GPIO进行配置,开启相应的时钟,选择相关引脚,设置浮空输入模式等。
void key_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*使能GPIO的RCC时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
/*配置PB11~PB14引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
2.配置好按键的GPIO口后,编写按键扫描函数,从而达到调整时间的功能。
u8 flag,mark;//flag为定时器启停标志位,mark为位选择标志位
//mark为0表示未选中,mark为1表示选择时位,mark为2表示选择分位,mark为3表示选择秒位
void keyscan(void)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==RESET)
{
delay_ms(10);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==RESET)
{
flag = ~flag;
if(!flag)
{
TIM_Cmd(TIM2, ENABLE);
}
else
{
TIM_Cmd(TIM2, DISABLE);
mark = 0;
}
}while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==RESET);
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==RESET)
{
delay_ms(10);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==RESET)
{
mark = mark>=3?0:mark+1;
}while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==RESET);
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==RESET)
{
delay_ms(10);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==RESET)
{
if(flag)
{
switch(mark)
{
case 1:hour = hour<23?hour+1:0;break;
case 2:min = min<59?min+1:0;break;
case 3:sec = sec<59?sec+1:0;break;
default:break;
}
}
}while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==RESET);
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==RESET)
{
delay_ms(10);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==RESET)
{
if(flag)
{
switch(mark)
{
case 1:hour = hour>0?hour-1:23;break;
case 2:min = min>0?min-1:59;break;
case 3:sec = sec>0?sec-1:59;break;
default:break;
}
}
}while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==RESET);
}
}
至此,我们完成了时钟显示的功能,当然,后期如果可以的话,我们可以使用stm32的RTC实时时钟资源,还可以设置闹钟、整点报时的功能。
本章,我主要介绍了如何利用stm32的TIM定时器和GPIO资源,实现时钟显示和按键调整的功能。下一章中,我将介绍如何利用DHT11模块来测量温度和湿度,从而实现系统对环境参量的获取。
绛旓細stm32涓嶅悓浜51,鍏辨湁11涓畾鏃跺櫒,鍏朵腑2涓珮绾ф帶鍒跺畾鏃跺櫒(TIM1鍜孴IM8),4涓櫘閫氬畾鏃跺櫒(TIM2~TIM5)鍜2涓熀鏈畾鏃跺櫒(TIM6鍜孴IM7),浠ュ強2涓湅闂ㄧ嫍瀹氭椂鍣ㄥ拰1涓郴缁熸淮绛斿畾鏃跺櫒銆傝繖閲,鎴戜滑閲囩敤鏅氬畾鏃跺櫒TIM2,骞朵笖寮鍚畾鏃跺櫒鐨勪腑鏂,涓柇鏃堕棿涓1s,骞朵笖鍦ㄤ腑鏂嚱鏁伴噷,妯℃嫙鏃堕挓鐨勮鏃鍔熻兘銆 (1)閰嶇疆宓屽涓柇鎺у埗鍣∟VIC ...
绛旓細STM32骞冲彴鎻愪緵浜嗗绉鏃堕挓婧愶紝涓昏鍖呮嫭HSI锛堥珮閫熷唴閮級銆丠SE锛堥珮閫熷閮級銆丩SI锛堜綆閫熷唴閮級鍜孡SE锛堜綆閫熷閮級銆傝繖浜涙椂閽熸簮鐨勯鐜囪寖鍥村洜鍏蜂綋鐨凷TM32绯诲垪鍜屽瀷鍙疯屽紓锛屼絾閫氬父鏈変竴瀹氱殑鏍囧噯鑼冨洿銆1. HSI锛堥珮閫熷唴閮ㄦ椂閽燂級锛氳繖鏄竴涓唴閮≧C鎸崱鍣紝閫氬父鐨勯鐜囪寖鍥村湪64 KHz鍒板嚑鍗丮Hz涔嬮棿锛屽叿浣撳彇鍐充簬STM32鐨鍨嬪彿...
绛旓細閲囩敤澶氭椂閽绯荤粺鐨勫師鍥犱富瑕佹湁浠ヤ笅鍑犵偣锛1. 鍔熻椾紭鍖栵細涓嶅悓鐨勫璁惧拰鍔熻兘妯″潡鍙兘闇瑕佷笉鍚岀殑宸ヤ綔棰戠巼銆傞氳繃鎻愪緵澶氫釜鏃堕挓婧愶紝STM32鍙互鏍规嵁瀹為檯闇姹傞夋嫨閫傚綋鐨勬椂閽棰戠巼锛屼粠鑰屼紭鍖栧姛鑰椼備緥濡傦紝褰撴煇涓璁句笉闇瑕侀珮閫熻繍琛屾椂锛屽彲浠ュ皢鍏舵椂閽熼鐜囬檷浣庯紝浠ュ噺灏戝姛鑰椼2. 鎬ц兘鎻愬崌锛氭煇浜涘姛鑳芥ā鍧楋紝濡侫DC锛堟ā鏁拌浆鎹㈠櫒锛夋垨...
绛旓細榛樿鎯呭喌涓嬶紝SetSysClock()鍑芥暟浼氬皢HSE璁剧疆涓168MHz锛屼粠鑰岃鐢熷嚭HCLK銆丳CLK1鍜孭CLK2绛夊叧閿鏃堕挓銆傛洿娣卞叆鐞嗚В锛STM32F429鎷ユ湁浜斾釜鏍稿績鏃堕挓婧愶細LSI锛32kHz鐨勪綆鍔熻楁椂閽燂級銆丩SE锛堢ǔ瀹氫笖浣庨熺殑32.768kHz鏃堕挓锛夈丠SE锛8MHz锛屽閮ㄦ垨鍐呴儴閫夋嫨锛夈丠SI锛16MHz锛変互鍙澶氬姛鑳PLL銆侾LL锛岀壒鍒槸涓籔LL锛岀敱HSE鎴朒SI椹...
绛旓細涓涓绔犱腑,鎴戝甫鐫澶у瀹炵幇浜鏃堕挓鏄剧ず鍜屾寜閿皟鏁鐨勫姛鑳銆傚湪杩欎竴绔犱腑,鎴戝皢鍒╃敤DHT11娓╂箍搴︿紶鎰熷櫒,鏉ユ祴閲忕幆澧冩俯搴﹀拰婀垮害銆 DHT11娓╂箍搴︿紶鎰熷櫒鏄暟瀛楀紡鐨,鍖呮嫭1涓數闃诲紡鎰熸箍鍏冧欢鍜1涓狽TC娴嬫俯鍏冧欢,鍐呴儴鑷甫AD杞崲鍔熻兘,閲囩敤鍗曟荤嚎,鍏锋湁鍝嶅簲蹇佹姉骞叉壈鑳藉姏寮恒佹т环姣旈珮绛夌壒鐐广傝妯″潡鎬诲叡4涓紩鑴,鍏朵腑涓や釜鏄數婧愬紩鑴歏CC...
绛旓細浣犺鐭ラ亾涓轰粈涔堥渶瑕佹椂閽熴鍗曠墖鏈蹇呴』瑕佹湁鏃堕挓鎵嶈兘姝e父杩愯锛STM32鏈夊閮ㄦ椂閽熷拰鍐呴儴鏃堕挓鐨勫尯鍒備絾鏃犺鏄閮ㄨ繕鏄唴閮ㄦ椂閽燂紝閮戒細缁忚繃鍒嗛鎴栧嶉鏈鍚庡緱鍒板璁鐨勬椂閽锛岃繖鏍峰璁炬墠鑳芥甯歌繍琛屻傝屾墦寮鏃堕挓灏辨槸鍏佽鎺ユ敹鍒嗛鍚庣殑棰戠巼銆傛瘮濡傚閮ㄦ椂閽熸櫠鎸綘鏄8M锛岀粡杩囧嶉鍚庡緱鍒72M锛岀劧鍚庡彲鍒嗛2銆4銆6銆8鈥︹︾粰ADC鏄...
绛旓細鏈汉鍐欎簡涓涓緢绠鍗曠殑stm32鐨鏅氬畾鏃跺櫒tim2鐨勪腑鏂▼搴忥紝瀹炵幇1绉掑畾鏃讹紝閫氳繃涓柇鏉ュ疄鐜伴棯鐏備絾鏄綋鎶婄▼搴忛噷鐨勬墍鏈塼im2鎹㈡垚tim1,涔熷氨鏄彉鎴愰珮绾у畾鏃跺櫒瀹氭椂锛岀▼搴忓叾浠栫殑鍏ㄩ兘娌℃敼锛屽彲鏄彂鐜颁腑鏂殑閫熷害鐢1绉掑彉鎴愪簡20澶氱锛屼负浠涔堝憿锛屼笉鐞嗚В鍟娿倀im1鐨勬椂閽鍜宼im2鐨勬椂閽熻缃殑閮芥槸72M鍟娿備负浠涔坱im1灏卞彉鎱...
绛旓細鍦STM32F40X绯诲垪寰帶鍒跺櫒涓紝鏃堕挓鏍戣璁¤嚦鍏抽噸瑕侊紝瀹冨喅瀹氫簡鑺墖鍐呭悇涓ā鍧楃殑杩愯棰戠巼鍜屽崗浣滄柟寮忋傞鍏堬紝鎴戜滑鍏虫敞鐨勬槸CPU鐨勪富棰戯紝瀹冮氬父璁惧畾涓168 MHz锛屼絾瀹為檯鎿嶄綔涓紝閫氳繃鐏垫椿閰嶇疆鏃堕挓鏍戯紝鍙互璋冩暣鍒版洿楂樼殑鎬ц兘銆傛椂閽熸爲妗嗘灦鐢卞嚑涓叧閿儴鍒嗙粍鎴愶紝鍖呮嫭AHB銆丄PB2鍜孉PB1鍩燂紝瀹冧滑鍚勮嚜鎵胯浇鐫涓嶅悓鐨勫姛鑳锛屽伐浣...
绛旓細涓昏鏈夊唴閮ㄤ綆閫鏃堕挓锛屽唴閮ㄩ珮閫熸椂閽燂紝澶栭儴楂橀熸椂閽熴佸閮ㄤ綆閫熸椂閽燂紝浣庨熸椂閽熶富瑕佺敤浜嶳TC锛岄珮閫熸椂閽熺敤浣滀富鏃堕挓銆
绛旓細閫氬父鎯呭喌涓嬶紝stm32鐨勬椂閽棰戠巼鏄72MHz鎴栬呮洿楂樸傚亣璁緎tm32鐨勬椂閽熼鐜囨槸72MHz锛堝嵆姣忕閽熻兘杩涜72000000娆℃搷浣滐級锛岄偅涔堝氨鍙互璁$畻鍑1鑷鍒27000闇瑕佺殑鏃堕棿銆傛椂闂达紙绉掞級 = 澧為噺 / 鏃堕挓棰戠巼鍏朵腑锛屽閲忎负27000锛屾椂閽熼鐜囦负72000000銆傛墍浠ワ紝鏃堕棿锛堢锛= 27000 / 72000000 鈮 0.000375 绉掑皢绉掕浆鎹负姣锛...