1、PWM介紹
PWM (Pulse Width Modulation) ,中文名為脈沖寬度調制,它能使用數字信號達到一個模擬信號的效果,脈沖寬度調制就是改變脈沖寬度來實現不同的效果。下面看圖10-1三組脈沖信號。
它是一個周期為10ms,頻率為100Hz的波形,每組高低電平脈沖寬度各不相同,也就是占空比(指高電平的時間占整個周期的比例)不同。
在數字電路中,只有0和1兩種狀態,在小燈中,0熄滅,1點亮。當讓小燈亮滅間隔運行時,并且間隔時間不斷減小,頻率大于100Hz,肉眼看起來為一直保持亮狀態,每個周期內不斷改變小燈亮和滅的時間,小燈亮度也會發生變化,這就達到模擬電路的效果,不再是純粹的0和1,還有亮度的不斷變化。
2、51單片機RAM區域劃分
51單片機RAM區域分為片內RAM和片外RAM兩部分。片內RAM和片外RAM的地址不是連起來的。現在幾乎51單片機芯片內部都集成了片外RAM。下面是C51中不同RAM的關鍵字和其地址。
data:片內 RAM 從 0x00~0x7F。
idata:片內 RAM 從 0x00~0xFF。
pdata:片外 RAM 從 0x00~0xFF。
xdata:片外 RAM 從 0x0000~0xFFFF。
-說明:STC89C52RC共有512字節RAM,分為256字節片內RAM和256字節片外RAM,data 是 idata 的一部分,pdata 是 xdata 的一部分。
內部RAM,默認定義的變量為定義在data區域,data區域RAM的訪問直接尋址,執行速度最快。idata為間接尋址,速度比data慢。通常不希望訪問到0x80–0xFF,因為這塊通常用于中斷和函數調用的堆棧,所以通常不用idata區域。
外部RAM,pdata和xdata都是通過間接尋址訪問,xdata的訪問速度最慢,但xdata訪問范圍最廣。
3、數碼管掃描函數算法改進
原代碼
P0 = 0xFF; //顯示消隱
switch(i)
{
case 0: ADDR2 = 0; ADDR1 = 0; ADDR0 = 0; i++; P0 = Ledbuff[0];break;
case 1: ADDR2 = 0; ADDR1 = 0; ADDR0 = 1; i++; P0 = Ledbuff[1];break;
case 2: ADDR2 = 0; ADDR1 = 1; ADDR0 = 0; i++; P0 = Ledbuff[2];break;
case 3: ADDR2 = 0; ADDR1 = 1; ADDR0 = 1; i++; P0 = Ledbuff[3];break;
case 4: ADDR2 = 1; ADDR1 = 0; ADDR0 = 0; i++; P0 = Ledbuff[4];break;
case 5: ADDR2 = 1; ADDR1 = 0; ADDR0 = 1; i=0; P0 = Ledbuff[5];break;
default:break;
}
改進后代碼
P0 = 0xFF;//關閉所有的段選位,顯示消隱
P1 = (P1 & 0xF8) | i; //位選索引值賦值到P1口低三位
P0 = Ledbuf[i];//緩沖區中索引位置的數據送到P0口
i++; //索引遞增循環,遍歷整個緩沖區
if(i > 5)
{
i = 0;
}
4、長短按鍵應用-模擬定時炸彈小程序
//長短按鍵應用
#include sbit ADDR3 = P1^3; sbit ENLED = P1^4; sbit BUZZ = P1^6; sbit KEY_IN_1 = P2^4; sbit KEY_IN_2 = P2^5; sbit KEY_IN_3 = P2^6; sbit KEY_IN_4 = P2^7; sbit KEY_OUT_1 = P2^3; sbit KEY_OUT_2 = P2^2; sbit KEY_OUT_3 = P2^1; sbit KEY_OUT_4 = P2^0; unsigned char code LedChar[] = { //數碼管顯示字符轉換表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; unsigned char LedBuff[]={ //數碼管+獨立LED顯示緩沖區 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; unsigned char KeySta[4][4] = { //全部矩陣按鍵的當前狀態 {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1} }; unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到標準鍵盤鍵碼的映射表 { 0x31, 0x32, 0x33, 0x26 }, //數字鍵1、數字鍵2、數字鍵3、向上鍵 { 0x34, 0x35, 0x36, 0x25 }, //數字鍵4、數字鍵5、數字鍵6、向左鍵 { 0x37, 0x38, 0x39, 0x28 }, //數字鍵7、數字鍵8、數字鍵9、向下鍵 { 0x30, 0x1B, 0x0D, 0x27 } //數字鍵0、ESC鍵、 回車鍵、 向右鍵 }; unsigned long pdata KeyDownTime[4][4] = { //每個按鍵按下的持續時間,單位ms {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }; bit flag1s = 0; //1s定時標志 bit flagStart = 0;//倒計時啟動標志 bit enBuzz = 0; //蜂鳴器是使能標志 unsigned long CountDown = 0;//倒計時計數器 unsigned char T0RH; //T0重載值的高字節 unsigned char T0RL;// T0重載值的低字節 void ConfigTimer0(unsigned char ms); void Shownumber(unsigned long num); void KeyDriver(); void KeyAction(unsigned char keycode); void Keyscan(); void Ledscan(); void main() { EA = 1; //使能總中斷 ENLED = 0;//選擇數碼管和獨立的LED ADDR3 = 1; ConfigTimer0(1);//配置T0定時1ms Shownumber(0);//上電顯示 while(1) { KeyDriver();//調用按鍵驅動函數 if(flag1s && flagStart)//倒計時啟動且1秒定時到達時,處理倒計時 { flag1s = 0; if(CountDown > 0) //倒計時未到達0時,計數器遞減 { CountDown--; Shownumber(CountDown); //刷新倒計時數顯示 if(CountDown == 0) //減到0時,執行聲光警報 { enBuzz = 1; //啟動蜂鳴器發聲 LedBuff[6] = 0x00;//點亮獨立LED } } } } } //配置并啟動T0,ms-T0定時時間 void ConfigTimer0(unsigned char ms) { unsigned long tmp; //臨時變量 tmp = 11059200 / 12; //定時器計數頻率 tmp = (tmp * ms) / 1000;//計算所需要的計數值 tmp = 65536 - tmp + 28; //計算定時器重載值,并補償中斷延時造成的誤差 T0RH = (unsigned char)(tmp >> 8);//定時器重載值拆分為高低字節 T0RL = (unsigned char)tmp; TMOD &= 0xF0;//清零T0的控制位 TMOD |= 0x01;//配置T0為模式一 TH0 = T0RH; //加載T0重載值 TL0 = T0RL; ET0 = 1;//使能T0中斷 TR0 = 1;//啟動T0 } //將一個無符號長整型的數字顯示到數碼管上,num為待顯示數字 void Shownumber(unsigned long num) { signed char i; unsigned char buf[6]; for(i = 0; i < 6; i++)//把長整型數轉換為6位十進制的數組 { buf[i] = num % 10; num /= 10; } for(i = 5; i >= 1; i--)//從高位起,遇到0轉換為空格,遇到非0則退出循環 { if(buf[i] == 0) { LedBuff[i] = 0xFF; } else { break; } } for(; i>= 0; i--) //剩余低位都如實轉換為數碼管的顯示字符 { LedBuff[i] = LedChar[buf[i]]; } } //按鍵驅動函數,檢測按鍵動作,調動相應動作函數,需在主循環中調用 void KeyDriver() { unsigned char i, j; static unsigned char pdata backup[4][4] = { //按鍵值備份,保存前一次的值 {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1} }; static unsigned long pdata Timethr[4][4] = { //快速輸入執行的時間閾值 {1000,1000,1000,1000},{1000,1000,1000,1000}, {1000,1000,1000,1000},{1000,1000,1000,1000} }; for(i = 0; i< 4; i++) //循環掃描4*4的矩陣按鍵 { for(j = 0; j < 4; j++) { if(backup[i][j] != KeySta[i][j])//檢測矩陣動作 { if(backup[i][j] != 0) //矩陣按下時執行動作 { KeyAction(KeyCodeMap[i][j]);//調用按鍵動作函數 } backup[i][j] = KeySta[i][j]; //刷新前一次備份值 } if(KeyDownTime[i][j] > 0) //檢測執行快速輸入 { if(KeyDownTime[i][j] >= Timethr[i][j]) { //達到閾值時執行一次動作 KeyAction(KeyCodeMap[i][j]);//調用按鍵動作函數 Timethr[i][j] += 200; //時間閾值增加200ms,以備下次執行 } } else //按鍵彈起時復位閾值時間 { Timethr[i][j] = 1000; //恢復1s的初始閾值時間 } } } } //按鍵動作函數,根據鍵碼執行相應的操作,keycode為按鍵鍵碼 void KeyAction(unsigned char keycode) { if(keycode == 0x26) //向上按鍵,倒計時設定值遞增 { if(CountDown < 9999) //最大計時9999秒 { CountDown++; Shownumber(CountDown); } } if(keycode == 0x28)//向下按鍵,倒計時設定值遞減 { if(CountDown > 1) //最小計時一秒 { CountDown--; Shownumber(CountDown); } } if(keycode == 0x0D)//回車鍵,啟動倒計時 { flagStart = 1; //啟動倒計時 } if(keycode == 0x1B) //ESC鍵,取消倒計時 { flagStart = 0; //停止倒計時 LedBuff[6] = 0xFF;//關閉獨立LED enBuzz = 0; //關閉蜂鳴器 CountDown =0; //倒計時數歸零 Shownumber(CountDown); } } //T0中斷服務函數,完成數碼管,按鍵掃描與秒定時 void InerruptTimer0() interrupt 1 { static unsigned int tmr1ms = 0;//1s定時器 TH0 = T0RH; //重新加載重載值 TL0 = T0RL; if(enBuzz == 1) { BUZZ = ~BUZZ;//驅動蜂鳴器發聲 } else BUZZ = 1;//關閉蜂鳴器 Ledscan();//Led掃描顯示 Keyscan(); //按鍵掃描 if(flagStart)//倒計時啟動時處理1秒定時 { tmr1ms++; if(tmr1ms >= 1000) { tmr1ms = 0; flag1s = 1; } } else //倒計時未啟動時1秒定時器歸零 { tmr1ms = 0; } } //LED動態掃描函數,需在定時中斷中調用 void Ledscan() { static unsigned char i = 0; //動態掃描索引 P0 = 0xFF; //關閉所有段選位,顯示消隱 P1 = (P1 & 0xF8) | i;//位選索引值賦值到P1口低3位 P0 = LedBuff[i];//緩沖區中索引位置的數據送到P0口 i++; //索引遞增循環,遍歷整個緩沖區 if(i > 6) { i = 0; } } void Keyscan() { unsigned char i; static unsigned char keyout = 0; //矩陣按鍵掃描輸出索引 static unsigned char keybuf[4][4] = {//矩陣按鍵掃描緩沖區 {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF} }; //將一行的4個按鍵值移入緩沖區 keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1; keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2; keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3; keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4; //消抖后更新按鍵狀態 for(i = 0; i < 4; i++) //每行四個按鍵,所以循環四次 { if((keybuf[keyout][i] & 0x0F) == 0x00) { //連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的按下 KeySta[keyout][i] = 0; KeyDownTime[keyout][i] += 4; //按下的持續時間累加 } else if((keybuf[keyout][i] & 0x0F) == 0x0F) { //連續4次掃描值為1,即4*4ms內都是彈起狀態時,可認為按鍵已穩定的彈起 KeySta[keyout][i] = 1; KeyDownTime[keyout][i] = 0;//按下持續時間清零 } } //執行下一次的掃描輸出 keyout++; //輸出索引遞增 keyout &= 0x03; //索引值加到4即歸零 switch(keyout) //根據索引,釋放當前輸出引腳,拉低下次的輸出 { case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0;break; case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0;break; case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0;break; case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0;break; default: break; } }
上一篇:【自學51單片機】12 --- 1602液晶初步認識
下一篇:【自學51單片機】9 -- 步進電機原理、蜂鳴器原理,單片機IO
推薦閱讀
史海拾趣
FOSLINK公司自成立以來,始終將技術創新視為企業發展的核心驅動力。在早期,公司專注于研發高性能的電子元器件,如混合積體電路(IC)和單石數位積體電路(ASIC)。通過不斷的技術積累和優化,FOSLINK成功推出了多款具有行業領先地位的產品,不僅滿足了市場對高質量電子元器件的需求,還引領了行業的技術進步。這一系列的創新成果,使FOSLINK在電子行業中逐漸嶄露頭角,贏得了眾多客戶的信賴和好評。
CANOPUS的產品逐漸贏得了全球音樂愛好者的喜愛。為了更好地滿足市場需求,公司開始積極拓展海外市場。通過與當地經銷商合作、參加國際展覽等方式,CANOPUS的產品逐漸打入國際市場,并在全球范圍內建立了良好的聲譽。
Elcoma公司在其早期發展階段,就致力于電子技術的研發和創新。他們成功研發出一種新型高效能的電子芯片,這一突破性的技術大大提高了電子設備的性能和效率。這一創新技術迅速在行業內引起了廣泛關注,許多大型電子設備制造商紛紛與Elcoma合作,希望將這一技術應用到他們的產品中。Elcoma憑借這一技術突破,逐漸在電子行業中嶄露頭角。
昭華(CHA)公司自2007年成立以來,就致力于撥碼開關與輕觸開關的研發制造。在初創階段,公司面臨著技術挑戰、資金短缺以及市場競爭激烈等多重困難。然而,昭華團隊憑借著對技術的熱情和執著,通過不斷的技術創新和產品優化,逐漸在市場上樹立了自己的品牌。他們不僅成功研發出多款高性能的開關產品,還積累了豐富的行業經驗,為公司的后續發展奠定了堅實的基礎。
隨著新能源汽車市場的快速發展,銓力公司看到了新的發展機遇。于是,公司開始布局新能源汽車領域,研發和生產新能源汽車所需的電源和充電設備。通過不斷創新和拓展市場,銓力在新能源汽車領域也取得了顯著的成績,為公司的發展注入了新的動力。
這五個故事展示了銓力(ALLPOWER)公司在電子行業中的發展歷程和取得的成就。從創立初期的太陽能電源產品研發,到技術突破和產品升級,再到國際市場的拓展和產業鏈整合,以及新能源汽車領域的布局,銓力始終保持著創新的精神和進取的態度,不斷推動著公司的發展。
埃派克森微電子的創立可追溯到2002年,由高勇回國并帶領一支團隊創立。作為一家初創公司,埃派克森在創立初期就明確了以模擬系統級芯片為突破口的發展戰略。通過不斷的研發和創新,埃派克森成功開發了多款具有競爭力的芯片產品,逐漸在亞太與國際市場嶄露頭角。這一階段,公司的創新精神和堅持不懈的努力為后來的發展奠定了堅實基礎。
前段時間買的手機,配了一塊電池和一個座充,另外跟朋友去買手機送了一個直充轉座充的“小盒子”。都是很便宜的東東。這兩天把這兩款手機充電器拆開了,看了一下里面電路… 先拆開“”小盒子…里面稀稀散散幾個器件,先汗一把 (=o=!) ...… 查看全部問答∨ |
開關電源 ,模塊電源 ,軍品電源 穩壓電源 開關電源以其體積小巧、性能卓越、使用方便的顯著特點,在通信、網絡、工控、鐵路、軍事等領域日益得到廣泛的應用。很多系統設計人員已經意識到,正確合理地設計開關電源,可以省去電源設計 ...… 查看全部問答∨ |
初始密碼為000000,按1輸入密碼,按2修改密碼,仿真和電路圖都做好了,可惜的是我畫的pcb板跳線實在多,不好意思拿出來了!那位哪做的更好的,不妨做一下吧! [ 本帖最后由 冷楓yj 于 2009-5-17 09:23 編輯 ]… 查看全部問答∨ |
|
MIB是代理保存的設備狀態信息,那么如果設備自身信息以其他方式組織,比如共享內存、全局變量、結構體,那么只要發包時包含自身信息不是就可以了,是不是就可以不要什么mib文件,不必非得按照MIB文件的格式組織吧? 現在我想裸板編程,移植lwip,在 ...… 查看全部問答∨ |
|
昨天用填充零低格硬盤時選錯了硬盤,10秒之后覺得不對強行關機,把低格后的硬盤接在另一臺電腦上后,用WinHex查看mbr,不出所料,全部是0.從自己機器硬盤復制前446個字節后,后面64位分區表搞不定了。 我用數據修復軟 ...… 查看全部問答∨ |
我是一個新手拉 剛剛接觸EVC編程拉 哪個好心的幫幫忙拉 設置目錄快照后 可以檢查數據庫是不是連接正確拉 好象要一個用戶名 還有什么數據庫文件拉… 查看全部問答∨ |
本帖最后由 ddllxxrr 于 2016-1-7 17:12 編輯 片子是在淘寶上買的MSP430F1232,高速晶振在沒有軟件設置的時候竟然起振了,Jtag一直都連不上去。后來果斷換了一家實體店,片子一換上去就好了。以前買過51的假片,現在竟然買到430的啦!無良賣家是在 ...… 查看全部問答∨ |