???【藍(lán)橋杯嵌入式】專題正在持續(xù)更新中,原理圖解析?,各模塊分析?以及歷年真題講解?都已更新完畢,歡迎大家前往訂閱本專題??
??【藍(lán)橋杯嵌入式】藍(lán)橋杯第十屆省賽真題
??【藍(lán)橋杯嵌入式】藍(lán)橋杯第十二屆省賽程序真題
??【藍(lán)橋杯嵌入式】藍(lán)橋杯第十三屆省賽程序真題
??本系列專欄 - ??藍(lán)橋杯嵌入式_勾欄聽曲_0的博客
??歡迎大家 ??? ?點(diǎn)贊?? ?評(píng)論?? ?收藏??
??個(gè)人主頁 - ?勾欄聽曲_0的博客??
??希望本文能對(duì)你有所幫助,如有不足請(qǐng)指正,共同進(jìn)步吧??
??書咄咄,且休休,一丘一壑也風(fēng)流。??
目錄
題目
硬件框圖
功能要求
初始狀態(tài)說明
賽題分析
代碼實(shí)現(xiàn)
題目
硬件框圖
功能要求
??功能概述
????????1)通過PA1引腳輸出頻率、占空比可調(diào)節(jié)的脈沖信號(hào)。
? ? ? ? 2)通過PA7引腳完成脈沖捕獲功能,測(cè)量輸入到該引腳的信號(hào)頻率。
????????3)通過微控制器的ADC 功能,檢測(cè)電位器R37上輸出的模擬電壓信號(hào)。
????????4)依試題要求,通過 LCD、LED完成數(shù)據(jù)顯示、報(bào)警指示等功能。
????????5)依試題要求,通過按鍵完成界面配置、參數(shù)設(shè)置等功能。
??性能要求
????????1)按鍵響應(yīng)時(shí)間:≤0.1秒。
????????2)指示燈動(dòng)作響應(yīng)時(shí)間:≤0.2秒。
??PWM輸出(PA1)
????????1)低頻模式:輸出信號(hào)頻率為4KHz。
????????2)高頻模式:輸出信號(hào)頻率為8KHz。
????????PA1輸出信號(hào)占空比可以通過電位器R37進(jìn)行調(diào)節(jié),關(guān)系如下圖所示
????????當(dāng)模式切換時(shí),在保證占空比不變的前提下,頻率在5秒內(nèi)均勻的升高或降低到目標(biāo)頻率,要求頻率步進(jìn)值小于200Hz。
??頻率測(cè)量(PA7)
????????測(cè)量輸入到PA7引腳的信號(hào)頻率,并將其轉(zhuǎn)換為速度值,速度值(v)與頻率值(f)的對(duì)應(yīng)關(guān)系:
????????其中f 單位為Hz,R和K作為參數(shù),可以通過按鍵進(jìn)行調(diào)整,n取小數(shù)點(diǎn)后2位有效數(shù)字。
??顯示功能
????????1)數(shù)據(jù)界面
????????????????顯示要素包括界面名稱(DATA)、PWM輸出模式(M、實(shí)時(shí)占空比(P)、實(shí)時(shí)速度(V)。
????????????????實(shí)時(shí)速度取小數(shù)點(diǎn)后1位有效數(shù)字。
????????????????輸出模式以“H”表示高頻模式、“L”表示低頻模式,模式切換未完成前,屏幕顯示的輸出模式保持不變。
????????2)參數(shù)界面
????????????????顯示要素包括界面名稱(PARA)、參數(shù)R和K的當(dāng)前值,R值和K值有效范圍1-10,整數(shù)。
? ? ? ? 3)統(tǒng)計(jì)界面
????????????????顯示要素包括:界面名稱(RECD)、PWM輸出模式切換次數(shù)(N)、高頻和低頻模式下的速度最大值。
????????????????MH:高頻模式最大速度,ML:低頻模式最大速度,顯示保留小數(shù)點(diǎn)后1位有效數(shù)字。
????????4) LCD通用顯示要求
????????????????顯示背景色(BackColor):黑色
? ? ? ????????? 顯示前景色(TextColor):白色
????????????????數(shù)據(jù)項(xiàng)與對(duì)應(yīng)的數(shù)據(jù)之間使用“=”間隔開。
????????????????請(qǐng)嚴(yán)格按照?qǐng)D示3、4、5要求設(shè)計(jì)各個(gè)信息項(xiàng)的名稱(區(qū)分字母大小寫)和行列位置。
??按鍵功能
????????1)B1:定義為“界面”按鍵,按下Bl按鍵可以往復(fù)切換數(shù)據(jù)、參數(shù)和記錄三個(gè)界面,切換模式如下圖所示。
????????2)B2:定義為“選擇”按鍵。
????????????????在數(shù)據(jù)界面下,用于切換選擇低頻或高頻模式。按鍵按下后,5秒內(nèi)不可再次觸發(fā)切換功能。
? ? ? ????????? 在參數(shù)界面下,按下B2按鍵,切換選擇R或K參數(shù)。每次從數(shù)據(jù)界面進(jìn)入?yún)?shù)界面,默認(rèn)當(dāng)前可調(diào)整的參數(shù)為R參數(shù);從參數(shù)界面退出時(shí),新的R參數(shù)和K參數(shù)生效。
????????3)B3:定義為“加”按鍵。
????????????????在參數(shù)界面下,按下B3按鍵,當(dāng)前可調(diào)整的參數(shù)加1,參數(shù)調(diào)整模式:
… 1? 2? 3? 4? …? 10? 1? 2? 3? …
????????4)B4:定義為“減”按鍵。
????????????????在參數(shù)界面下,按下B4按鍵,當(dāng)前可調(diào)整的參數(shù)減1,參數(shù)調(diào)整模式:
… 2? 1? 10? 9? …? 2? 1? 10? 9? …
????????????????在數(shù)據(jù)界面下,長(zhǎng)按B4按鍵超過2秒后松開(長(zhǎng)按鍵),可以“鎖定”占空比調(diào)整功能,此時(shí)輸出信號(hào)占空比保持不變,不受R37電位器輸出電壓控制;處于“鎖定”狀態(tài)后,再次按下B4按鍵(短按鍵),實(shí)現(xiàn)“解鎖”功能,恢復(fù)R37電位器對(duì)輸出信號(hào)占空比的控制。
要求:
????????按鍵應(yīng)進(jìn)行有效的防抖處理,避免出現(xiàn)一次按鍵動(dòng)作觸發(fā)多次功能等情形。
????????按鍵動(dòng)作不應(yīng)影響數(shù)據(jù)采集過程和屏幕顯示效果。
????????有效區(qū)分長(zhǎng)、短按鍵功能,互不影響。
????????參數(shù)調(diào)整應(yīng)考慮邊界值,不出現(xiàn)無效參數(shù)。
????????當(dāng)前界面下無功能的按鍵按下,不觸發(fā)其它界面的功能。
??統(tǒng)計(jì)功能
????????1)低頻模式、高頻模式切換次數(shù)(N)。
? ? ? ? 2)高頻、低頻輸出模式下的最大速度分開統(tǒng)計(jì),保持時(shí)間不足2秒的速度值不納入統(tǒng)計(jì)。
??LED指示燈功能
????????1) LD1:處于數(shù)據(jù)界面,指示燈LD1點(diǎn)亮,否則熄滅。
????????2) LD2:低頻模式、高頻模式切換期間,指示燈LD2以0.1秒為間隔切換亮、滅狀態(tài),模式切換完成后熄滅。
????????3) LD3:占空比調(diào)整處于“鎖定”狀態(tài)時(shí),指示燈LD3點(diǎn)亮,否則熄滅。4)LD4-LD8指示燈始終處于熄滅狀態(tài)。
初始狀態(tài)說明
????????請(qǐng)嚴(yán)格按照下列要求設(shè)計(jì)作品上電后的初始狀態(tài):
????????1)參數(shù)R為1。
????????2)參數(shù)K為1。
????????3)切換次數(shù)N為0。
????????4)PWM輸出模式為低頻模式。
????????5)處于“解鎖”狀態(tài),R37電位器可以控制信號(hào)占空比。
????????6)處于數(shù)據(jù)顯示界面。
賽題分析
? ? ? ? 今年的賽題與最近幾屆又較大的不同,近幾屆都是老三樣(LED,按鍵,LCD)加串口再加一個(gè)模塊組成,而今年沒考串口,換成了脈沖捕獲,而PWM輸出也與以往有些不同,并不是簡(jiǎn)單的改一下頻率或占空比,而是要使用的輸出模擬電壓經(jīng)過一些換算來修改占空比,同時(shí)還有一共坑下面我們?cè)僦v解這個(gè)坑。還有就是會(huì)有更多細(xì)節(jié)上的要求,包括按鍵的長(zhǎng)按也是很久沒考過的點(diǎn)了。
? ? ? ? 簡(jiǎn)單看一下硬件框圖,得知考點(diǎn)主要有老三樣(LED,按鍵,LCD),加脈沖捕獲,模擬輸入,PWM輸出。
? ? ? ? 看一下功能概述,這里也許有些同學(xué)會(huì)有點(diǎn)混,因?yàn)槠匠?赡苁怯肞A7引腳做PWM輸出。但這次不一樣。PA1引腳才是做PWM輸出的,而PA7引腳是用來完成脈沖捕獲的。同時(shí)要檢測(cè)R37的模擬信號(hào)。
? ? ? ? 我們看到PWM模塊,PWM一共要求有兩種輸出模式,低頻與高頻,我們使用相關(guān)庫函數(shù)更改PA1引腳的自動(dòng)重裝載值即可。第二點(diǎn),PA1的PWM輸出占空比是由R37電位器的電壓決定的,看圖得知是一共分段函數(shù),R37的電壓在1V一下時(shí),占空比為10%,在3V以上時(shí),占空比為85%,中間部分就是線性增長(zhǎng)了。因?yàn)槭蔷€性的,所以解一個(gè)一元一次方程即可,解出來為:Y=37.5x-27.5(Y:占空比,單位%,X:R37通過ADC轉(zhuǎn)換的電壓。接下來大坑來啦,還要求我們?cè)诟哳l與低頻模式切換時(shí)占空比要保持不變,并且,并且啊,重點(diǎn)來啦,并且頻率的改變要在5秒內(nèi)均勻變化,并且頻率的每次變化不超過200Hz。
? ? ? ? 我們現(xiàn)在重點(diǎn)來講講這個(gè)是怎么坑的,要怎么解。首先解決頻率變化時(shí)保持占空比不變,這一點(diǎn)不算復(fù)雜,因?yàn)轭l率是通過改變自動(dòng)重裝載值來改變的,我們只需要獲取當(dāng)前PA1的自動(dòng)重裝載值然后乘上占空比的百分比,再將這個(gè)值代入改變占空比的函數(shù)即可。而這個(gè)頻率的均勻變化是怎么個(gè)均勻法呢。也許有些同學(xué)把這個(gè)均勻的概念直接加到用來修改頻率的自動(dòng)重裝載值上,嘿嘿,如果這樣,這個(gè)坑就被你踩實(shí)了。比如說,初始狀態(tài)是低頻,設(shè)置預(yù)分頻系數(shù)為“100”,自動(dòng)重裝載值為“200”,這樣的頻率就為4000Hz了,要像頻率升到8000Hz,那么自動(dòng)重裝載值就要降到“100”,但重點(diǎn)是均勻變化,這個(gè)均勻不是指200到100這個(gè)數(shù)值均勻變化,而是頻率均勻變化。所以應(yīng)該以頻率的變化來改變自動(dòng)重裝載值。
? ? ? ? 現(xiàn)在坑也說完了,我們開始正式說這個(gè)問題怎么解決。要求每次變化不大于200Hz,我們就讓它每次改變100Hz吧,假設(shè)頻率現(xiàn)在為4000Hz,要變?yōu)?000Hz,就要改變自動(dòng)重裝載值40次,又要求5秒內(nèi)完成變化,那就每0.1秒改變一次吧。第一次變化成4100Hz,那么自動(dòng)重裝載值就變成了80MHz/100(預(yù)分頻系數(shù))/4100取下整,所以每次改變自動(dòng)重裝載值,只需要先將存儲(chǔ)頻率的那個(gè)變量加100,然后代入上述的式子中就可以得到相應(yīng)的自動(dòng)重裝載值啦。然后用相關(guān)函數(shù)改變自動(dòng)重裝載值就可以啦。(記住上面說的,頻率變化的同時(shí),占空比也不能改變哦)我們來看一下這部分的代碼實(shí)現(xiàn):
if(flag_k2 == 1) //按鍵2被按下的標(biāo)志,這一部分只在按鍵被按下后執(zhí)行一次
{
flag_5s = 1; //5s內(nèi)按鍵2不能進(jìn)行操作的定時(shí)器標(biāo)志,開啟這個(gè)定時(shí)器
flag_k2 = 0;
num ++;
if(plv_pa1<200) //plv_pa1:PA1的頻率,小于200,即按鍵按下前為低頻
{
flag_100 = 1; //按鍵按下前為低頻的標(biāo)志
}
else if(plv_pa1 > 100) //按鍵按下前為高頻
{
flag_200 = 1; //按鍵按下前為高頻的標(biāo)志
}
}
if(flag_5s > 0 && flag_5s <= 400) //flag_5s:5秒的定時(shí),每10毫秒加一,加到500重置為0
//這一部分是0.1秒中斷執(zhí)行一次的計(jì)時(shí)器里面,所以0到400一共執(zhí)行40次,共耗時(shí)4秒。
{
if(deng == 0) //LED2循環(huán)閃爍的標(biāo)志
{
TurnOn_LED(2);
deng++;
}
else
{
TurnOff_LED(2);
deng = 0;
}
if(flag_100 == 1) //如果是低頻
{
plv_pa1 = 8000/(--f48); //這里將公式80Mhz/100(預(yù)分頻系數(shù))/頻率,簡(jiǎn)化了一下
}
if(flag_200 == 1) //如果是高頻
{
plv_pa1 = 8000/(++f48);
}
? ? ? ? 我們接著往下看,接下來的模塊是脈沖捕獲,脈沖捕獲雖然好幾年都沒考過了,但是實(shí)現(xiàn)起來不算太難,也因?yàn)榻鼛啄甓紱]考這個(gè)模塊,本系列專題中也沒有這個(gè)模塊的講解,如果有需要可在評(píng)論區(qū)留言,我再單獨(dú)出一篇文章這脈沖捕獲。然后這里也不是捕獲后直接輸出,還要經(jīng)過一個(gè)公式的計(jì)算然后輸出加速度,這里就不展開講啦,會(huì)在下面的代碼實(shí)現(xiàn)中具體講怎么寫的。
? ? ? ? 再往下就是LCD的顯示功能了,每個(gè)字母位于幾行幾列,每個(gè)參數(shù)保留幾位小數(shù)等細(xì)節(jié)注意一下就可以啦。需要特別注意的是數(shù)據(jù)界面中,“H”或“L”的變化要在頻率完全改變完后再改變。
? ? ? ? 按鍵比以往多了一個(gè)長(zhǎng)按,除此之外與往年形式都差不多了。
? ? ? ? 所謂統(tǒng)計(jì)功能就是記錄一下某些數(shù)值,也不用EEPROM來存儲(chǔ)。
? ? ? ? LED模塊就是常談的閃爍與亮滅了。
? ? ? ? 至此,題目就分析完畢,哪些是難點(diǎn)重點(diǎn)想必大家心中有所定見了,接下來我們就開始搓代碼吧。
代碼實(shí)現(xiàn)
? ? ? ? 個(gè)人代碼,僅供參考與討論,解題思路最重要??
? ? ? ? ??中斷模塊
? ? ? ? ? ? ? ? 使用的是TIM3,10毫秒中斷一次,里面實(shí)現(xiàn)了4個(gè)按鍵的單擊,一個(gè)按鍵的長(zhǎng)按,頻率的均勻變化,占空比的變化等。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i = 0;i < 4; i++ )
{
switch (key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta==0)
{
key[i].judge_sta = 1; //第一次判斷是否按下
key[i].key_time = 0;
}
}
break;
case 1:
{
if(key[i].key_sta==0) //進(jìn)入下一次定時(shí)器掃描,按鍵還是按下狀態(tài),那么就確認(rèn)為按下,以此來消抖
{
key[i].judge_sta = 2;
}
else
key[i].judge_sta = 0;
}
break;
case 2:
{
if(key[i].key_sta==1) //判斷是否松手
{
if(key[i].key_time < 100)
{
key[i].key_flag = 1;
}
if(key[i].key_time > 100) //一次掃描10毫秒,100次1000毫秒,就是判斷是否長(zhǎng)按超過1000毫秒
//松手后,才會(huì)執(zhí)行相應(yīng)反應(yīng)
{
key[i].long_flag = 1;
}
key[i].judge_sta = 0;
key[i].key_time = 0;
}
else
{
key[i].key_time++;
}
}
break;
}
}
if(a++ == 10) //0.1s
{
a = 0;
if(flag_k2 == 1) //按鍵2被按下的標(biāo)志,這一部分只在按鍵被按下后執(zhí)行一次
{
flag_5s = 1; //5s內(nèi)按鍵2不能進(jìn)行操作的定時(shí)器標(biāo)志,開啟這個(gè)定時(shí)器
flag_k2 = 0;
num ++;
if(plv_pa1<200) //plv_pa1:PA1的頻率,小于200,即按鍵按下前問低頻
{
flag_100 = 1; //按鍵按下前為低頻的標(biāo)志
}
else if(plv_pa1 > 100) //按鍵按下前為高頻
{
flag_200 = 1; //按鍵按下前為高頻的標(biāo)志
}
}
if(flag_5s > 0 && flag_5s <= 400) //flag_5s:5秒的定時(shí),每10毫秒加一,加到500重置為0
//這一部分是0.1秒中斷執(zhí)行一次的計(jì)時(shí)器里面,所以0到400一共執(zhí)行40次,共耗時(shí)4秒。
{
if(deng == 0) //LED2循環(huán)閃爍的標(biāo)志
{
TurnOn_LED(2);
deng++;
}
else
{
TurnOff_LED(2);
deng = 0;
}
if(flag_100 == 1) //如果是低頻
{
plv_pa1 = 8000/(--f48); //這里將公式80Mhz/100(預(yù)分頻系數(shù))/頻率,簡(jiǎn)化了一下
}
if(flag_200 == 1) //如果是高頻
{
plv_pa1 = 8000/(++f48);
}
if(flag_5s > 402) //5秒定時(shí)計(jì)數(shù)超過402
{
if(flag_100 == 1)
{
plv_pa1 = 200;
flag_100 = 0;
}
if(flag_200 == 1)
{
plv_pa1 = 100;
flag_200 = 0;
}
}
__HAL_TIM_SetAutoreload(&htim2,plv_pa1);
}
pa7_duty = getADC(&hadc2);
if(pa7_duty <= 1 && flag_s == 0)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,plv_pa1*0.1);
pa1 = 10;
}
else if(pa7_duty >= 3 && flag_s == 0)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,plv_pa1*0.85);
pa1 = 85;
}
else if(flag_s == 0)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,plv_pa1*(0.375*pa7_duty-0.275));
pa1 = 37.5*pa7_duty-27.5;
}
}
if(flag_5s >0)
{
flag_5s+=1;
if(flag_5s > 500)
{
flag_5s = 0;
TurnOff_LED(2);
}
}
}
}
? ? ? ? ??脈沖捕獲
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕獲計(jì)數(shù)器 頻率測(cè)量
{
if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)//中斷消息來源 選擇直接輸入的通道
{
tim_val1= HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//獲取計(jì)數(shù)器1的值
__HAL_TIM_SetCounter(htim,0);//計(jì)數(shù)器歸零
frq = 1000000/tim_val1; //frq=時(shí)鐘(80m)/prescaler(80)/tim_val1
HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_1);
}
}
? ? ? ? ??按鍵模塊
void key_proc()
{
if(key[0].key_flag == 1)
{
view++;
if(view==3) view=0;
if(view == 0)
{
TurnOn_LED(1);
flag_r = 0;
}
else
{
TurnOff_LED(1);
}
LCD_Clear(Black);
key[0].key_flag = 0;
}
if(key[1].key_flag == 1)
{
if(view == 0 && flag_k2 == 0)
{
flag_k2 = 1;
}
else if(view == 1)
{
flag_r++;
if(flag_r == 2)
{
flag_r = 0;
}
}
key[1].key_flag = 0;
}
if(key[2].key_flag == 1)
{
if(view == 1)
{
if(flag_r == 0)
{
R++;
if(R == 11)
R = 1;
}
else
{
K++;
if(K == 11)
K = 1;
}
}
key[2].key_flag = 0;
}
if(key[3].key_flag == 1)
{
if(view == 1)
{
if(flag_r == 0)
{
R--;
if(R == 0)
R = 10;
}
else
{
K--;
if(K == 0)
K = 10;
}
}
if(view == 0)
{
flag_s = 0;
TurnOff_LED(3);
}
key[3].key_flag = 0;
}
if(key[3].long_flag == 1)
{
if(view ==0)
{
flag_s = 1;
TurnOn_LED(3);
}
key[3].long_flag = 0;
}
}
? ? ? ? ??LCD模塊文章來源:http://www.zghlxwxcb.cn/news/detail-413827.html
void disp_proc()
{
Vs = frq*2*3.14*R/(100*K);
if(plv_pa1 >= 200)
{
if(Vs > V_max)
{
V_max = Vs;
}
}
else if(plv_pa1 < 105)
{
if(Vs > V_min)
{
V_min = Vs;
}
}
if(view==0)
{
char text[30];
sprintf(text," DATA ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
if(plv_pa1 == 200) //頻率完全改變完后改變M的值
{
sprintf(text," M=L ");
LCD_DisplayStringLine(Line3, (uint8_t *)text);
}
else if(plv_pa1 == 100)
{
sprintf(text," M=H ");
LCD_DisplayStringLine(Line3, (uint8_t *)text);
}
sprintf(text," p=%d%% ",pa1);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
sprintf(text," V=%.1f ",Vs);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
else if(view==1)
{
//disp_clear();
char text[30];
sprintf(text," PARA ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," R=%d ",R);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," k=%d ",K);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
}
else if(view==2)
{
//disp_clear();
char text[30];
sprintf(text," RECD ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," n=%d ",num);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," MH=%.1f ",V_max);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
sprintf(text," ML=%.1f ",V_min);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
}
????????希望本篇文章對(duì)你有所收獲,如有疑問或其他問題可在評(píng)論區(qū)留言??文章來源地址http://www.zghlxwxcb.cn/news/detail-413827.html
到了這里,關(guān)于【藍(lán)橋杯嵌入式】藍(lán)橋杯嵌入式第十四屆省賽程序真題,真題分析與代碼講解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!