91视频免费?看_蜜芽MY188精品TV在线观看_国产免费无遮挡在线观看视频_深夜国产_亚洲精品欧洲精品_欧美黑人粗暴多交

  • 回復
  • 收藏
  • 點贊
  • 分享
  • 發新帖

吳堅鴻單片機程序技巧與模式連載

QQ截圖20140211133146

吳堅鴻

擁有多年電子開發經驗,功力深厚,目前經營獨立工作室。

主攻PIC,瑞薩,STC,51系列等各類單片機的開發,擅長使用VHDL語言開發CPLD,精通使用VC,VB開發電腦上位機軟件。

本文作者認為傳授單片機技術最好要有一個學習板作為硬件平臺,即使沒有硬件平臺,至少每個程序也要有相對應的硬件原理圖。但在本文當中作者將所有的硬件原理都用中文來描述,盡可能確保讀者看文字就知道硬件電路大概的原理。

文章中所有程序都是用C語言并且基于PIC單片機,因為對于讀者來說,所有單片機的C語言都大同小異,只要學會一種,其他的都懂了。而相對的,程序側重點轉移到了教大家編程的模式與框架上。

本文文章每一節的程序里主要包含兩方面的內容。一方面是程序框架,另一方面是項目中所遇到的某個具體技術難題的解決方法。

全部回復(5)
正序查看
倒序查看
一木01
LV.3
2
2014-02-11 13:41

一)按鍵行列掃描與蜂鳴器

 

(1)技術體會:在行列式掃描結構的薄膜按鍵里,干擾很大,按鍵掃描程序非常講究,尤其是去抖動的處理。

(2)功能需求:每按一個按鍵,蜂鳴器就響一次。

(3)硬件原理:

(a)用4個IO來做2X2按鍵行列掃描,其中作為輸入的2個IO口必須接上拉電阻20K左右。

(b)用1個IO經過8050三極管來驅動有源蜂鳴器,有源蜂鳴器通電就一直響,斷電就停止。而無源蜂鳴器是要靠斷斷續續的開關信號來驅動才能響,就是要頻率來驅動。

(4)源碼適合的單片機:PIC18F4620,晶振為22.1184MHz

(5)源代碼講解如下:

#include //包含芯片相關頭文件

//補充說明:吳堅鴻程序風格是這樣的,凡是輸出IO后綴都是_dr,凡是輸入的//IO后綴都//是_sr

#define beep_dr LATA1 //蜂鳴器輸出

#define key_dr1 LATB3 //2X2按鍵行輸出

#define key_dr2 LATB4 //2X2按鍵行輸出

#define key_sr1 RB6 //2X2按鍵行輸入

#define key_sr2 RB7 //2X2按鍵行輸入

//補充說明:吳堅鴻程序風格是這樣的,凡是做延時計數閥值的常量

//前綴都用cnt_表示。

#define cnt_delay_cnt1 25 //按鍵去抖動延時閥值

#define cnt_delay_cnt2 5 //按鍵行輸出信號穩定的小延時閥值

#define cnt_voice_time 60 //蜂鳴器響的聲音長短的延時閥值

void delay1(unsigned int de) ;//小延時程序,時間不宜太長,因為內部沒有喂看門狗

//補充說明:吳堅鴻程序風格是這樣的,凡是按鍵掃描函數都放在定時中

//斷里,凡是按鍵服務程序都是放在main函數循環里。有人說不應該把子程序//放在中斷里,別聽他們,信鴻哥無坎坷。

void key_scan(); //按鍵掃描函數,放在定時中斷里

void key_service(); //按鍵服務函數,放在main函數循環里

//補充說明:吳堅鴻程序風格是這樣的,凡是switch()語句括號里面的變量名

//后綴都用_step表示。

unsigned char key_step=1; //按鍵掃描步驟變量,在switch()語句的括號里

//補充說明:吳堅鴻程序風格是這樣的,凡是按鍵或者感應輸入的自鎖變量名

//后綴都用_lock表示。

unsigned char key_lock1=0; //按鍵自鎖標志

//補充說明:吳堅鴻程序風格是這樣的,凡是計數器延時的變量

//后綴都用_cnt表示。

unsigned int delay_cnt1=0; //延時計數器的變量

unsigned int delay_cnt2=0; //延時計數器的變量

unsigned int voice_time_cnt; //蜂鳴器響的聲音長短的計數延時

//補充說明:吳堅鴻程序風格是這樣的,凡是做類型的變量的分類

//后綴都用_sec表示。

Unsigned char key_sec=0; //哪個按鍵被觸發

//主程序

main()

{

ADCON0=0x00;

ADCON1=0x0f; //全部為數字信號

ADCON2=0xa1; //右對齊

RBPU=0; //上拉電阻

SSPEN=0; //決定RA5不作為串口

TRISB3=0; //配置按鍵行掃描IO為輸出

TRISB4=0; //配置按鍵行掃描IO為輸出

TRISB6=1; //配置按鍵列掃描IO為輸入

TRISB7=1; //配置按鍵列掃描IO為輸入

T1CON=0x24; //定時器中斷配置

TMR1H=0xF5;

TMR1L=0x5F;

TMR1IF=0;

TMR1IE=1;

TMR1ON=1;

TMR1IE=1;

//補充說明,以上的內容為寄存器配置,每種不同的單片機會有點差異,

//大家不用過度關注以上寄存器的配置,只要知道有這么一回事即可

beep_dr=0; //關蜂鳴器,上電初始化IO

while(1)

{

CLRWDT(); //喂看門狗,大家不用過度關注此行

key_service(); //按鍵服務

}

}

void key_scan() //按鍵掃描函數

{

//補充說明:如果中斷一次就把所有的按鍵都掃描完,中斷占用的時間片就會太多,勢//必會影響main函數里其他子程序的運行,為了避免一口氣把所//的按鍵都掃描完,此

//處用switch語句把4個按鍵分成2等分,一次中斷只掃描2個按鍵

switch(key_step) //按鍵掃描步驟,

{

case 1: //掃描1號鍵,2號鍵

key_dr1=0; //按鍵行掃描輸出第一行低電平

key_dr2=1;

delay_cnt2=0; //延時計數器清零

key_step++; //切換到下一個運行步驟

break;

case 2:

delay_cnt2++;

if(delay_cnt2>cnt_delay_cnt2) //小延時,但不是去抖動延時,替代一直受網友爭議的delay1(40)

{

delay_cnt2=0;

key_step++; //切換到下一個運行步驟

}

break;

case 3:

if(key_sr1==1&&key_sr2==1)

{ //如果沒有按鍵按下,則2個IO輸入都是高電平

key_step++; //如果沒有按鍵按下,下一個中斷掃描下2個

0
回復
一木01
LV.3
3
2014-02-11 13:43

//按鍵

key_lock1=0; //按鍵自鎖標志清零

delay_cnt1=0; //按鍵去抖動延時計數器清零,此行非常巧妙

}

Else if(key_sr1==0&&key_sr2==1&&key_lock1==0)

{ // key_lock1按鍵自鎖,避免按鍵一直觸發,下降沿有效

++delay_cnt1; //延時計數器

//補充說明:有按鍵觸發之后,不要馬上響應,要延時一段時間去抖動,此處本人設計非常

//巧妙,很多人僅僅知道按鍵延時的時候要保證還能去處理別的程序,這樣是還不夠的,

//在延時去抖動的時候,還必須要監控延時這段時間里,按鍵IO輸入口是否會由于受到某//種干擾突然由低變成高,如果一旦變成高,那么延時計數器delay_cnt1必須重新清零

//我當年就是因為這樣處理,把賣給富士康100臺受干擾死機的設備修好了,老板馬上

//給我加薪1000元。

if(delay_cnt1>cnt_delay_cnt1) //延時計數器超過一定的數值

{

delay_cnt1=0;

key_lock1=1; //自鎖按鍵置位,避免一直觸發,只有松開按鍵,

//此標志位才會被清零

key_sec=1; //觸發1號鍵

}

}

else if(key_sr1==1&&key_sr2==0&&key_lock1==0)

{

++delay_cnt1;

if(delay_cnt1>cnt_delay_cnt1)

{

delay_cnt1=0;

key_lock1=1; //自鎖按鍵置位,避免一直觸發

key_sec=2; //觸發2號鍵

}

}

break;

case 4: //掃描//掃描3號鍵,4號鍵

key_dr1=1;

key_dr2=0; //按鍵行掃描輸出第二行低電平

delay_cnt2=0; //延時計數器清零

key_step++; //切換到下一個運行步驟

break;

case 5:

delay_cnt2++;

if(delay_cnt2>cnt_delay_cnt2) //小延時,但不是去抖動延時,替代一直受網友爭議的delay1(40)

{

delay_cnt2=0;

key_step++; //切換到下一個運行步驟

}

break;

case 6:

if(key_sr1==1&&key_sr2==1)

{

key_step++;

key_lock1=0;

delay_cnt1=0;

}

Else if(key_sr1==0&&key_sr2==1&&key_lock1==0)

{

++delay_cnt1;

if(delay_cnt1>cnt_delay_cnt1)

{

delay_cnt1=0;

key_lock1=1;

key_sec=3; //觸發3號鍵

}

}

else if(key_sr1==1&&key_sr2==0&&key_lock1==0)

{

++delay_cnt1;

if(delay_cnt1>cnt_delay_cnt1)

{

delay_cnt1=0;

key_lock1=1; //自鎖按鍵置位,避免一直觸發

key_sec=4; //觸發4號鍵

}

}

break;

}

0
回復
一木01
LV.3
4
2014-02-11 13:44

if(key_step>6) //第1組按鍵與第2組按鍵反復輪流掃描

{

key_step=1;

}

}

void key_service() //按鍵服務函數

{

switch(key_sec) //按鍵服務狀態切換

{

case 1:// 1號鍵

// 補充說明:voice_time_cnt只要不為0蜂鳴器就會響,中斷里判斷voice_time_cnt不為0

//時,會不斷自減,一直到它為0時,自動把蜂鳴器關閉

voice_time_cnt= cnt_voice_time; //蜂鳴器響“滴”一聲就停

key_sec=0; //相應完按鍵處理程序之后,把按鍵選擇變量清零,

//避免一直觸發

break;

case 2:// 2號鍵

voice_time_cnt= cnt_voice_time; //蜂鳴器響“滴”一聲就停

key_sec=0; //相應完按鍵處理程序之后,把按鍵選擇變量清零,

//避免一直觸發

break;

case 3://3號鍵

voice_time_cnt= cnt_voice_time; //蜂鳴器響“滴”一聲就停

key_sec=0; //相應完按鍵處理程序之后,把按鍵選擇變量清零,

//避免一直觸發

break;

case 4://4號鍵

voice_time_cnt= cnt_voice_time; //蜂鳴器響“滴”一聲就停

key_sec=0; //相應完按鍵處理程序之后,把按鍵選擇變量清零,

//避免一直觸發

break;

}

}

//中斷

void interrupt timer1rbint(void)

{

if(TMR1IE==1&&TMR1IF==1) //定時中斷

{

TMR1IF=0; //定時中斷標志位關閉

TMR1ON=0; //定時中斷開關關閉

key_scan(); //按鍵掃描函數

if(voice_time_cnt) //控制蜂鳴器聲音的長短

{

beep_dr=1; //蜂鳴器響

--voice_time_cnt; //蜂鳴器響的聲音長短的計數延時

}

else

{

beep_dr=0; //蜂鳴器停止

}

TMR1H=0xF5; //重新設置定時時間間隔

TMR1L=0x5F;

TMR1ON=1; //定時中斷開關打開

}

}

void delay1(unsigned int de)

{

unsigned int t;

for(t=0;t

}

(6)小結:

以上是我常用的編程結構。后續我做的所有項目基本上是這樣一種編程結構。這一節技術上要特別重視按鍵掃描。有按鍵觸發之后,不要馬上響應,要延時一段時間去抖動,此處本人設計非常巧妙,很多人僅僅知道按鍵延時的時候要保證還能去處理別的程序,這樣是還不夠的,在延時去抖動的時候,還必須要監控延時這段時間里,按鍵IO輸入口是否會由于受到某種干擾突然由低變成高,如果一旦變成高,那么延時計數器delay_cnt1必須重新清零,我當年就是因為這樣處理,把賣給富士康100臺受干擾死機的設備修好了,老板馬上給我加薪1000元。

 

 

待續

0
回復
tanik
LV.5
5
2017-03-07 22:44
@一木01
if(key_step>6)//第1組按鍵與第2組按鍵反復輪流掃描{key_step=1;}}voidkey_service()//按鍵服務函數{switch(key_sec)//按鍵服務狀態切換{case1://1號鍵//補充說明:voice_time_cnt只要不為0蜂鳴器就會響,中斷里判斷voice_time_cnt不為0//時,會不斷自減,一直到它為0時,自動把蜂鳴器關閉voice_time_cnt=cnt_voice_time;//蜂鳴器響“滴”一聲就停key_sec=0;//相應完按鍵處理程序之后,把按鍵選擇變量清零,//避免一直觸發break;case2://2號鍵voice_time_cnt=cnt_voice_time;//蜂鳴器響“滴”一聲就停key_sec=0;//相應完按鍵處理程序之后,把按鍵選擇變量清零,//避免一直觸發break;case3://3號鍵voice_time_cnt=cnt_voice_time;//蜂鳴器響“滴”一聲就停key_sec=0;//相應完按鍵處理程序之后,把按鍵選擇變量清零,//避免一直觸發break;case4://4號鍵voice_time_cnt=cnt_voice_time;//蜂鳴器響“滴”一聲就停key_sec=0;//相應完按鍵處理程序之后,把按鍵選擇變量清零,//避免一直觸發break;}}//中斷voidinterrupttimer1rbint(void){if(TMR1IE==1&&TMR1IF==1)//定時中斷{TMR1IF=0;//定時中斷標志位關閉TMR1ON=0;//定時中斷開關關閉key_scan();//按鍵掃描函數if(voice_time_cnt)//控制蜂鳴器聲音的長短{beep_dr=1;//蜂鳴器響--voice_time_cnt;//蜂鳴器響的聲音長短的計數延時}else{beep_dr=0;//蜂鳴器停止}TMR1H=0xF5;//重新設置定時時間間隔TMR1L=0x5F;TMR1ON=1;//定時中斷開關打開}}voiddelay1(unsignedintde){unsignedintt;for(t=0;t}(6)小結:以上是我常用的編程結構。后續我做的所有項目基本上是這樣一種編程結構。這一節技術上要特別重視按鍵掃描。有按鍵觸發之后,不要馬上響應,要延時一段時間去抖動,此處本人設計非常巧妙,很多人僅僅知道按鍵延時的時候要保證還能去處理別的程序,這樣是還不夠的,在延時去抖動的時候,還必須要監控延時這段時間里,按鍵IO輸入口是否會由于受到某種干擾突然由低變成高,如果一旦變成高,那么延時計數器delay_cnt1必須重新清零,我當年就是因為這樣處理,把賣給富士康100臺受干擾死機的設備修好了,老板馬上給我加薪1000元。  待續
這么好的文章,居然沒有人贊?等待后續。
0
回復
ruohan
LV.9
6
2017-03-23 13:17
@tanik
這么好的文章,居然沒有人贊?等待后續。

推薦本書看看了

0
回復
主站蜘蛛池模板: 交城县| 潼关县| 浏阳市| 松溪县| 游戏| 双辽市| 永胜县| 灵武市| 绵竹市| 宜章县| 汝阳县| 永嘉县| 运城市| 绍兴市| 东明县| 会同县| 清涧县| 左云县| 武强县| 涞水县| 蒙自县| 东台市| 商南县| 灯塔市| 武隆县| 原平市| 威海市| 青神县| 巩留县| 芦溪县| 自治县| 习水县| 姚安县| 襄樊市| 正镶白旗| 麟游县| 祁东县| 布尔津县| 临沧市| 眉山市| 汝州市|