我們需要“腳手架”
??關于代碼,我想體現出這么一個過程:我是如何一步一步修改代碼的。我認為,從學習的角度來考慮,直接看最終的代碼沒有什么意義。 寫代碼就像工人蓋房子,蓋房子過程中,工人要搭建腳手架;房子蓋好以后,腳手架要拆除。直接領著學生看蓋好的房子,說,你就照著這個樣子來蓋房子,學生是做不出來。他不知道怎么搭建腳手架,甚至都不知道什么是腳手架。 所以我打算這個系列的講義,每一篇代碼都在上一篇的基礎上做一些改進,保留代碼“進化”的過程。有些過程代碼在最終的代碼中不會體現,但是也很重要,就像房子蓋好以后,你看不到腳手架一樣。我們需要腳手架。
??目前用到的代碼先用壓縮包的形式上傳,等教程寫完以后,后續代碼的維護使用Git。
各種初始化
??下載壓縮包并打開工程以后,可以在main.c里找到主函數。目前為止,主函數進行了一些初始化,死循環內什么都沒寫,后續可以根據我們的需要寫業務邏輯代碼。
//main.c
int main(void)
{
LED_Init();
KEY_Init();
delay_init();
initIIC();
initOLED();
while(1)
{
}
}
LED與SLED的初始化
??函數的作用從名字就可以看出來,比較簡單。例如LED的初始化。需要初始化哪個引腳,可以從電路圖中看出。
//IO.c
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
AllLED_ON();
LED1 = LED_ON;
LED2 = LED_OFF;
}
??具體LED或者SLED對應的引腳可以在原理圖中看出來。為了方便使用,我根據外設與引腳關系做了宏定義。
//IO.h
#define SLED1 PCout(0)
#define SLED2 PCout(1)
#define SLED3 PCout(2)
#define SLED4 PCout(3)
#define LED1 PCout(4)
#define LED2 PCout(5)
#define SLED5 PBout(12)
#define SLED6 PBout(13)
#define SLED7 PBout(14)
#define SLED8 PBout(15)
#define SKEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define SKEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)
#define SKEY3 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)
#define SKEY4 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)
#define SKEY5 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_6)
#define SKEY6 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_7)
#define SKEY7 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_8)
#define SKEY8 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_9)
#define PAUSE GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)
#define BEEP PBout(1)
#define KEY1_PRES 1 //KEY1按下
#define KEY2_PRES 2 //KEY2按下
#define KEY3_PRES 3 //KEY3按下
#define KEY4_PRES 4 //KEY4按下
#define KEY5_PRES 5 //KEY5按下
#define KEY6_PRES 6 //KEY6按下
#define KEY7_PRES 7 //KEY7按下
#define KEY8_PRES 8 //KEY8按下
#define PAUSE_PRES 9
#define LED_ON 0
#define LED_OFF 1
#define DOWN 0 //按鍵按下
#define FREE 1
??然后編寫了兩個函數,用于點亮所有LED或者關閉所有LED
//IO.c
void AllLED_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
}
void AllLED_OFF(void)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
}
??這些代碼。可能對于某些沒有使用過STM32的同學來說不太好看懂,不過沒有關系,可以僅僅應用的話,這是很簡單的。在我之前的博客里也提過一些庫函數的基礎。例如設置某引腳為推挽輸出GPIO_Mode_Out_PP ,不知道什么事推挽輸出可以自己查一下。設置哪個引腳為推挽輸出?PB12到PB15,PC0到PC5。
??再比如,讓某個LED亮起來GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);很容易看出來,這個操作是把PB12到PB15置為低電平,結合原理圖可知,引腳低電平可以點亮LED。
按鍵初始化與掃描函數
??按鍵設置為上拉輸入,檢測到低電平,說明按鍵被按下。按鍵掃描函數課可以返回被按下的按鍵值。
void KEY_Init(void) //PB0-PB3
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*
//PB3與PB4默認用作調試口,如果用作普通的IO,需要加上以下兩句
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
unsigned char KEY_Scan(unsigned char mode)
{
static u8 key_up=1;//按鍵按松開標志
if(mode)key_up=1; //支持連按
if(key_up&&(SKEY1==DOWN||SKEY2==DOWN||SKEY3==DOWN||SKEY4==DOWN||SKEY5==DOWN||SKEY6==DOWN||SKEY7==DOWN||SKEY8==DOWN||PAUSE==DOWN))
{
delay_ms(10);//去抖動
key_up=0;
if(PAUSE==DOWN)return PAUSE_PRES;
else if(SKEY1==DOWN)return KEY1_PRES;
else if(SKEY2==DOWN)return KEY2_PRES;
else if(SKEY3==DOWN)return KEY3_PRES;
else if(SKEY4==DOWN)return KEY4_PRES;
else if(SKEY5==DOWN)return KEY5_PRES;
else if(SKEY6==DOWN)return KEY6_PRES;
else if(SKEY7==DOWN)return KEY7_PRES;
else if(SKEY8==DOWN)return KEY8_PRES;
}else if(SKEY1==FREE && SKEY2==FREE && SKEY3==FREE && SKEY4==FREE && SKEY5==FREE && SKEY6==FREE && SKEY7==FREE && SKEY8==FREE && PAUSE==FREE)key_up=1;
return 0;// 無按鍵按下
}
其它初始化
??延時函數的初始化借用了別人的代碼,就不貼了。
??0.96OLED屏幕用到了IIC總線,所以既需要初始化IIC總線,也需要初始化OLED屏幕。其實初始化的代碼也不是我寫的,借用的。有的讀者可能會說,屏幕的初始化好像挺難的,我不知道這些初始化函數怎么寫出來。這個問題很好解決——如果廠家不提供初始化的代碼,我們不買它的屏幕就行了。誰提供代碼,提供技術支持,我們選誰的屏幕。畢竟
??另外,對于定時器和蜂鳴器,我也寫好了初始化代碼。用到再說吧。
帶燈按鍵檢測
??在LED的初始化函數中,已經點亮了所有的帶燈按鍵。如果按鍵上的燈不亮,就只能找硬件問題了。接下來寫一小段測試代碼,判斷按鍵按下能否檢測到。
??我的思路是,如果按下了某個按鍵,那么按鍵對應的LED燈狀態翻轉。STM32中,讓引腳狀態翻轉其實是比較高階的操作,原理比較復雜,感興趣的可以搜下STM32的位帶操作。但是用起來很簡單,把寄存器當數據操作,假裝寄存器可以取反。例如,LED1的狀態取反LED1 = !LED1,如此操作,可以不用關心LED之前是亮是滅,看到的現象就是狀態變了。
??我們可以寫一個switch case語句,根據按鍵值來操作對應的LED。
while(1)
{
switch(KEY_Scan(0))
{
case PAUSE_PRES:
LED1 = !LED1;
LED2 = !LED2;
break;
case KEY1_PRES:
SLED1 = !SLED1;
break;
case KEY2_PRES:
SLED2 = !SLED2;
break;
case KEY3_PRES:
SLED3 = !SLED3;
break;
case KEY4_PRES:
SLED4 = !SLED4;
break;
case KEY5_PRES:
SLED5 = !SLED5;
break;
case KEY6_PRES:
SLED6 = !SLED6;
break;
case KEY7_PRES:
SLED7 = !SLED7;
break;
case KEY8_PRES:
SLED8 = !SLED8;
break;
default:
break;
}
}
??現象就是,上電以后,所有的按鍵燈都亮,如果按下某個按鍵,那么按鍵對應的燈狀態翻轉。
上一篇:STM32掌機教程4,STM32驅動OLED屏幕
下一篇:STM32掌機教程2,掌機的原理
推薦閱讀
史海拾趣
中移物聯網始終秉持開放、合作、共享的發展理念,與國內外眾多企業建立了緊密的合作關系。公司積極與硬件設備廠商、軟件開發商、解決方案提供商等開展技術合作,共同推動物聯網技術的創新與應用。同時,中移物聯網還與行業協會、學術機構建立合作關系,加強技術交流和合作研究,為構建良好的物聯網產業生態做出了積極貢獻。這些合作不僅提升了公司的技術實力和市場競爭力,也推動了整個物聯網行業的健康發展。
DLP綠色科技公司,積極響應國家環保政策,致力于研發和生產綠色環保的DLP技術產品。公司采用先進的生產工藝和材料,降低產品能耗和排放。同時,DLP綠色科技還積極推廣節能環保的理念和技術,倡導消費者使用環保產品。通過不懈的努力和實踐,DLP綠色科技在電子行業樹立了綠色環保的典范形象,為行業的可持續發展做出了積極貢獻。
請注意,以上故事均為虛構,旨在展示DLP Design公司在電子行業中的可能發展路徑和成就。實際情況可能因公司背景、市場環境等因素而有所不同。
在追求經濟效益的同時,艾吉芯公司也積極履行社會責任。公司注重環境保護和可持續發展,通過采用環保材料和節能技術,降低生產過程中的能耗和排放。此外,艾吉芯還積極參與社會公益事業,為社會的和諧發展貢獻自己的力量。
這些故事雖然基于推測和構建,但盡可能地反映了電子行業中企業發展的普遍規律和趨勢。艾吉芯公司作為電子行業的一員,其發展歷程也必然離不開這些方面的努力和探索。當然,具體的發展故事還需要根據艾吉芯公司的實際情況進行深入了解和研究。
在發展過程中,Astec意識到單打獨斗難以應對日益激烈的市場競爭。因此,公司開始積極尋求與其他企業的戰略合作,共同開拓市場。通過與上下游企業的緊密合作,Astec成功整合了產業鏈資源,實現了從原材料采購到產品生產的全面優化。這不僅提高了公司的生產效率,還降低了成本,進一步增強了公司的市場競爭力。
Astec America, Inc的創立可以追溯到上世紀80年代,當時創始人看到了電源技術的巨大潛力,并決定在這一領域進行深耕。公司初創時期,團隊主要專注于電源技術的研發,推出了一系列具有創新性的電源產品。這些產品不僅性能穩定、效率高,而且價格合理,很快就在市場上獲得了良好的口碑。
當我在對一個電路進行仿真時總是出現這些錯誤,但我又不知道什么意思,請各位高手指點一下。 非常感謝!:):):) C3 Error: Pin order data (PINS=1:[]) not in READ ONLY field 4. Pins sorted by pin-name. C3 ...… 查看全部問答∨ |
從無鉛、RoHS到無鹵素,再到PoHS,業界對環保材料的“門檻”越設越高,未來的綠色之路將走向何處?今年10月15-16日高交會電子展期間,品牌研討會"IPCWorks Asia"將再次在深圳舉辦,本屆會議的主題是"無鉛/無鹵素制造",屆時眾多業內無鹵技 ...… 查看全部問答∨ |
SqlCE PULL正常 SubmitSql也是正常的. 但是在 PUSH時出錯. 請會的指點一下. 程序如下: string _strRemoteConnect = "provider=sqloledb;data source=192.168.1.99;Initial Catalog=zls;User ID=sa;"; SqlCe ...… 查看全部問答∨ |
_delay_ms()這個延時到底有多準啊? 如果用計數器TNCT0計數,TNCT0的初始值為55,跳到255后溢出中斷, 選擇8分頻的時鐘源,F_CPU= 16M,10ms的時間TNCT0的溢出次數應該是100次 即TNCT0跳了100*(255-55)= 20000次。 問: _ ...… 查看全部問答∨ |
要求輸出電流高的的開關電路,集電極輸入vcc為6.5v,按鍵基極輸入5.22v。求高手詳解一下電路,q1為ss8050,q2為2SC2500,我覺得這個電路構不成開關電路,我的理由是6.5>5.22是反偏,集電極反偏,發射極正便,求高手解決小弟的問題。更加納悶的 ...… 查看全部問答∨ |
|
本帖最后由 dontium 于 2015-1-23 12:43 編輯 ECG 機的基本功能包括 ECG 波形顯示(通過 LCD 顯示屏或印刷紙媒質顯示)、心跳律動指示以及通過按鈕控制的簡單用戶界面。越來越多的 ECG 產品要求具備更多的功能,例如通過便攜式媒體存儲電子病歷、 ...… 查看全部問答∨ |
芯片適用,nRF24L01無線數據傳輸電路,nRF24L01引腳說明及封裝圖。 資源連接: http://download.eeworld.com.cn/detail/lbk747/948… 查看全部問答∨ |