?? pwm.c
字號:
/*------------------------------------------------------------------------------------*-
文 件 名:PWM.c
功 能:左右兩路PWM輸出,各自輸出周期可調,可顯示,脈沖寬度可調,可顯示。
調試結果完全符合要求
適用器件:51系列,這里使用P89V51RB2,用STC89C54仿真
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
#include "main.h"
#include "port.h"
static tWord RightPWM;
static tWord LeftPWM;
static tWord LPwmCnt;
static tWord RPwmCnt;
static tByte PwmWidth;
static tByte PwmWidt_R;
static tByte PwmWidt_L;
static tByte PwmDisp;
//顯示緩沖區
tByte xdata disnum[8]={0};
//共陽數碼管筆段碼 0 1 2 3 4 5 6 7 8 9 L R P -
tByte code dispcode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0xc7,0x88,0x8c,0xbf};
static bit KeyScanTask;
static bit ShapTask;
static bit ShapCheck;
static bit KeyProcessTask;
static bit DispTask;
/*------------------------------------------------------------------------------------*-
函數原形:tByte read165(void)
函數功能:從74LS165中讀數據
輸入參數:無
輸出參數:無
注 意:移位問題,詳細請看程序注釋,先關中斷,讀完數據再開
作 者:馮耿超
完成日期:2007-07-10
-*------------------------------------------------------------------------------------*/
tByte Read_165()
{
tByte dat_buf,cnt;
//數據鎖存
_165_sft=0;
dat_buf=0;
cnt=8;
//關中斷
EA = 0;
//開始移位
_165_sft=1;
do
{
_165_clk=0;
//這里要先移位,否則會出現最低位被補0而最高位被移出的現象
dat_buf<<=1;
if(_165_sda)
{
dat_buf|=0x01;
}
_165_clk=1;
}while(--cnt);
//開中斷
EA = 1;
//返回鍵值
return dat_buf;
}
void Key_Scan()
{
if(Read_165()!=0xff)
//檢測滿足,使能去抖動
ShapCheck = 1;
}
/*------------------------------------------------------------------------------------*-
*函數原形:Key_Board_Process()
*函數功能:鍵盤功能處理函數
*輸入參數:無
*輸出參數:無
*修改情況:修改按鍵功能,使得對應顯示時所以對應的按鍵才起作用,語句請看程序中帶*號的語句
*修改日期:200707-20
*作 者:馮耿超
*完成日期:2007-07-12
-*------------------------------------------------------------------------------------*/
void Key_Board_Process()
{
if(Read_165()!=0xff)
{
switch(Read_165())
{
//左邊PWM加
case 0xfe: if(PwmDisp ==0) //*
{
LeftPWM++;
if(LeftPWM>999)
LeftPWM = 999;
}
break;
//左邊PWM減
case 0xfd: if(PwmDisp ==0) //*
{
if(LeftPWM!=0)
LeftPWM--;
else
LeftPWM = 1;
}
break;
//右邊PWM加
case 0xfb: if(PwmDisp ==1) //*
{
RightPWM++;
if(RightPWM>999)
RightPWM = 999;
}
break;
//右邊PWM減
case 0xf7: if(PwmDisp ==1) //*
{
if(RightPWM!=0)
RightPWM--;
else
RightPWM = 1;
}
break;
//脈沖寬度加
case 0xdf: if(PwmDisp ==2) //*
{
PwmWidth++;
if(PwmWidth>250)
PwmWidth = 250;
}
break;
//脈沖寬度減
case 0xbf: if(PwmDisp ==2)
{
if(PwmWidth!=0)
PwmWidth--;
else
PwmWidth = 0;
}
break;
//選擇顯示值
case 0x7f: PwmDisp++;
if(PwmDisp==5)PwmDisp = 0;
break;
default: break;
}
}
}
/*------------------------------------------------------------------------------------*-
函數原形:void _138_drive_bit(tByte xdata led_bit)
函數功能:led位驅動,用74LS138作為位選,位選參數為led_bit
輸入參數:無
輸出參數:無
作 者:馮耿超
完成日期:2007-06-13
-*------------------------------------------------------------------------------------*/
void _138_drive_bit(tByte xdata led_bit)
{
switch(led_bit)
{
case 1:_138_a = 0;_138_b = 0;_138_c = 0; break;
case 2:_138_a = 1;_138_b = 0;_138_c = 0; break;
case 3:_138_a = 0;_138_b = 1;_138_c = 0; break;
case 4:_138_a = 1;_138_b = 1;_138_c = 0; break;
case 5:_138_a = 0;_138_b = 0;_138_c = 1; break;
case 6:_138_a = 1;_138_b = 0;_138_c = 1; break;
case 7:_138_a = 0;_138_b = 1;_138_c = 1; break;
case 8:_138_a = 1;_138_b = 1;_138_c = 1; break;
default:break;
}
}
/*------------------------------------------------------------------------------------*-
函數原形:void _164_send_data(tByte xdata led_code)
函數功能:將共陽數碼管筆段通過74LS164送出
輸入參數:無
輸出參數:無
注 意:74LS164為串入并出,時鐘先為上升沿觸發,先關中斷,送完數據再開
作 者:馮耿超
完成日期:2007-06-13
-*------------------------------------------------------------------------------------*/
void _164_send_data(tByte xdata led_code)
{
tByte data i;
EA = 0;
for(i=0;i<8;i++)
{
_164_sck = 0;
_164_sda = (led_code&0x80);
_164_sck = 1;
led_code<<=1;
}
EA = 1;
_164_sck = 0;
}
/*------------------------------------------------------------------------------------*-
函數原形:void display_led(tByte xdata led,tByte xdata num)
函數功能:把顯示筆段num送到指定的LED上,指定位為led
輸入參數:無
輸出參數:無
注 意:LED動態顯示按照關顯示——>送筆段——>開顯示的步驟,防止LED串紅
作 者:馮耿超
完成日期:2007-06-13
-*------------------------------------------------------------------------------------*/
void display_led(tByte xdata led,tByte xdata num)
{
//關LED顯示
_138_oe = 1;
//送顯示筆段到指定的LED上
switch(led)
{
case 1:_138_drive_bit(led);
_164_send_data(num);break;
case 2:_138_drive_bit(led);
_164_send_data(num);break;
case 3:_138_drive_bit(led);
_164_send_data(num);break;
case 4:_138_drive_bit(led);
_164_send_data(num);break;
case 5:_138_drive_bit(led);
_164_send_data(num);break;
case 6:_138_drive_bit(led);
_164_send_data(num);break;
case 7:_138_drive_bit(led);
_164_send_data(num);break;
case 8:_138_drive_bit(led);
_164_send_data(num);break;
default:break;
}
//開LED顯示
_138_oe = 0;
}
/*------------------------------------------------------------------------------------*-
函數原形:void display()
函數功能:在LED上從右到左顯示按鍵按下所對應的值
輸入參數:無
輸出參數:無
注 意:參數K的取值
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
void display()
{
static tByte cnt;
switch (PwmDisp)
{
//顯示左邊PWM值
case 0:
disnum[0] = LeftPWM%10;
disnum[1] = LeftPWM/10%10;
disnum[2] = LeftPWM/100%10;
disnum[3] = LeftPWM/1000%10;
//顯示“L”
disnum[4] = 13;
disnum[5] = 13;
disnum[6] = 13;
disnum[7] = 10;
break;
//顯示右邊PWM值
case 1:
disnum[0] = RightPWM%10;
disnum[1] = RightPWM/10%10;
disnum[2] = RightPWM/100%10;
disnum[3] = RightPWM/1000%10;
//顯示“R”
disnum[4] = 13;
disnum[5] = 13;
disnum[6] = 13;
disnum[7] = 11;
break;
//顯示脈沖高電平的寬度
case 2:
disnum[0] = PwmWidth%10;
disnum[1] = PwmWidth/10%10;
disnum[2] = PwmWidth/100%10;
disnum[3] = PwmWidth/1000%10;
//顯示“P”
disnum[4] = 13;
disnum[5] = 13;
disnum[6] = 13;
disnum[7] = 12;
break;
//右邊脈沖計數
case 3:
disnum[0] = RPwmCnt%10;
disnum[1] = RPwmCnt/10%10;
disnum[2] = RPwmCnt/100%10;
disnum[3] = RPwmCnt/1000%10;
disnum[4] = 13;
disnum[5] = 13;
disnum[6] = 12;
disnum[7] = 11;
break;
//左邊脈沖計數
case 4:
disnum[0] = LPwmCnt%10;
disnum[1] = LPwmCnt/10%10;
disnum[2] = LPwmCnt/100%10;
disnum[3] = LPwmCnt/1000%10;
disnum[4] = 13;
disnum[5] = 13;
disnum[6] = 12;
disnum[7] = 10;
break;
default:break;
}
//LED顯示器顯示
if(++cnt==8)cnt=0;
switch(cnt)
{
case 0:display_led(cnt+1,dispcode[disnum[7]]);break;
case 1:display_led(cnt+1,dispcode[disnum[6]]);break;
case 2:display_led(cnt+1,dispcode[disnum[5]]);break;
case 3:display_led(cnt+1,dispcode[disnum[4]]);break;
case 4:display_led(cnt+1,dispcode[disnum[3]]);break;
case 5:display_led(cnt+1,dispcode[disnum[2]]);break;
case 6:display_led(cnt+1,dispcode[disnum[1]]);break;
case 7:display_led(cnt+1,dispcode[disnum[0]]);break;
default:break;
}
}
/*------------------------------------------------------------------------------------*-
函數原形:void T0_Init()
函數功能:T0初始化,工作方式1,16位定時計數器,定時5ms作為系統時標
輸入參數:無
輸出參數:無
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
void T0_Init()
{
TMOD &=0xf0;
TMOD |=0x01;
//5ms中斷初值
TH0 = 0xec;
TL0 = 0x78;
ET0 = 1;
TR0 = 1;
EA = 1;
}
/*------------------------------------------------------------------------------------*-
函數原形:void Task_Init()
函數功能:系統任務初始化
輸入參數:無
輸出參數:無
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
void Task_Init()
{
//左右脈沖周期初始化
RightPWM = 100;
LeftPWM = 100;
LPwmCnt = 0;
RPwmCnt = 0;
//用于調節高電平脈沖的寬度,
//它必須小于脈沖周期,即PWM的中斷周期
PwmWidth = 30;
//左右邊高電平脈沖寬度
PwmWidt_R = 0;
PwmWidt_L = 0;
//默認顯示脈沖寬度值
PwmDisp = 2;
//鍵盤掃描任務初始化
KeyScanTask = 0;
//去抖動初始化
ShapCheck = 0;
//鍵盤處理任務初始化
KeyProcessTask = 0;
//LED顯示任務初始化
DispTask = 0;
}
/*------------------------------------------------------------------------------------*-
函數原形:系統主函數
函數功能:由PwmWidth可以計算高電平的寬度為5ms*20=100ms
低電平的寬度為RightPWM或是LeftPWM的初值乘以5ms減去100ms
輸入參數:無
輸出參數:無
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
void main()
{
//系統初始化
T0_Init();
Task_Init();
while(1)
{
//執行LED顯示任務
if(DispTask)
{
DispTask = 0;
display();
}
//保持高電平時間為PwmWidt_R*5ms
if(PwmWidt_R>0)
{
Right = 1;
}
else
{
Right = 0;
}
//保持高電平時間為PwmWidt_L*5ms
if(PwmWidt_L>0)
{
Left = 1;
}
else
{
Left = 0;
}
//鍵盤掃描任務
if(KeyScanTask)
{
KeyScanTask = 0;
Key_Scan();
}
//鍵盤處理任務
if(KeyProcessTask)
{
KeyProcessTask = 0;
Key_Board_Process();
}
}
}
/*------------------------------------------------------------------------------------*-
函數原形:void T0_ISR()
函數功能:T0中斷服務子程序
輸入參數:無
輸出參數:無
作 者:馮耿超
完成日期:2007-07-13
-*------------------------------------------------------------------------------------*/
void T0_ISR() interrupt 1 using 1
{
//右邊PWM寬度
static tByte RightPwmCnt = 0;
//左邊PWM寬度
static tByte LeftPwmCnt = 0;
//鍵盤掃描
static tByte KeyCnt = 0;
//鍵盤去抖動
static tByte ShapCnt = 0;
//重裝初值
TH0 = 0xec;
TL0 = 0x78;
//添加顯示任務
DispTask = 1;
//添加右邊PWM輸出
if(++RightPwmCnt==RightPWM)
{
RightPwmCnt = 0;
PwmWidt_R = PwmWidth;
Right = 1;
RPwmCnt++;
}
//添加左邊PWM輸出
if(++LeftPwmCnt==LeftPWM)
{
LeftPwmCnt = 0;
PwmWidt_L = PwmWidth;
Left = 1;
LPwmCnt++;
}
//150ms也就是30個時標執行一次鍵盤掃描
if(++KeyCnt==30)
{
KeyCnt = 0;
KeyScanTask = 1;
}
//是否允許去抖動開始
if(ShapCheck)
{
//去抖動時間為10ms
if(++ShapCnt==2)
{
//去抖動關閉
ShapCheck = 0;
//去抖動時長復位
ShapCnt = 0;
//添加鍵盤處理任務
KeyProcessTask = 1;
}
}
//左右兩邊PWM寬度調節
//注意這里的“--”符號位置
if(PwmWidt_R--==0)PwmWidt_R = 0;
if(PwmWidt_L--==0)PwmWidt_L = 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -