我這里有個實例,用的STC8H1K16,兩路pwm驅(qū)動兩個NMOS管控制雙色燈帶- /************* 功能說明 **************
- 按鍵短按開燈,開燈后3秒內(nèi),短按開關(guān)切換色溫(白光,黃光,自然光;切換色溫功率不變);
- 長按調(diào)亮度;超過3秒短按關(guān)燈。
- 設(shè)置的參數(shù)掉電保存;
- 高級PWM定時器 PWM1P/PWM1N,PWM2P/PWM2N,PWM3P/PWM3N,PWM4P/PWM4N 每個通道都可獨立實現(xiàn)PWM輸出,
- 或者兩兩互補對稱輸出.
- MCU: STC8H1K16 LQFP-32封裝
- P1.1 P1.2驅(qū)動兩路LED
- 2023/4/14 調(diào)試成功
- ******************************************/
- //#include "reg51.h" //包含此頭文件后,里面聲明的寄存器不需要再手動輸入,避免重復(fù)定義
- #include <stc8h.h>
- #include "intrins.h"
- #define MAIN_Fosc 11059200L //定義主時鐘
- #define PWM_PSCR 3 //設(shè)置分頻 頻率計算公式MAIN_Fosc/(PWM_PSCR+1)*(PWM_ARR+1)邊沿對齊
- #define PWM_ARR 1023 //設(shè)置周期值 頻率2.7KHz
- //#define PWM_PSCR 15 //設(shè)置分頻 頻率計算公式MAIN_Fosc/(PWM_PSCR+1)*(PWM_ARR+1)
- //#define PWM_ARR 254 //設(shè)置周期值 頻率2.7KHz
- #define uchar unsigned char
- #define uint unsigned int
- typedef unsigned char u8;
- typedef unsigned int u16;
- typedef unsigned long u32;
- /****************************** 用戶定義宏 ***********************************/
- #define Timer0_Reload (65536UL -(MAIN_Fosc / 1000)) //Timer 0 中斷頻率, 1000次/秒
- /*****************************************************************************/
- #define PWM1_1 0x00 //P:P1.0 N:P1.1
- #define PWM1_2 0x01 //P:P2.0 N:P2.1
- #define PWM1_3 0x02 //P:P6.0 N:P6.1
- #define PWM2_1 0x00 //P:P1.2/P5.4 N:P1.3
- #define PWM2_2 0x04 //P:P2.2 N:P2.3
- #define PWM2_3 0x08 //P:P6.2 N:P6.3
- #define PWM3_1 0x00 //P:P1.4 N:P1.5
- #define PWM3_2 0x10 //P:P2.4 N:P2.5
- #define PWM3_3 0x20 //P:P6.4 N:P6.5
- #define PWM4_1 0x00 //P:P1.6 N:P1.7
- #define PWM4_2 0x40 //P:P2.6 N:P2.7
- #define PWM4_3 0x80 //P:P6.6 N:P6.7
- #define PWM4_4 0xC0 //P:P3.4 N:P3.3
- #define ENO1P 0x01
- #define ENO1N 0x02
- #define ENO2P 0x04
- #define ENO2N 0x08
- #define ENO3P 0x10
- #define ENO3N 0x20
- #define ENO4P 0x40
- #define ENO4N 0x80
- /************* 本地變量聲明 **************/
- bit B_1ms; //1ms標志
- u16 PWM1_Duty;
- u16 PWM2_Duty;
- u16 PWM2_Dutyv;
- u16 PWM1_Dutyv;
- //u16 PWM3_Duty;
- //u16 PWM4_Duty;
- uchar PWM2_Dutyv_L;
- uchar PWM2_Dutyv_M;
- uchar temp_PWM2_Dutyv_L;
- uchar temp_PWM2_Dutyv_M;
- bit PWM1_Flag;
- bit PWM2_Flag;
- bit PWM3_Flag;
- bit PWM4_Flag;
- void UpdatePwm(void);
- sbit k2=P3^2;//燈開關(guān)
- sbit led=P1^2;//燈
- uint k1_cont,k2_cont;//按鍵消抖計時
- uchar k1_lock,k2_lock;//按鍵鎖
- uchar count1=10,count2=10;
- uint Long_cont=400;
- uint Long_cont1=200;
- uint Long_cont2=200;
- uchar PWM_Value; //占空比 變量
- bit PWM_UP_Down_Flag; //調(diào)光方向標志
- bit flag_short_k1,flag_short_k2;//按鍵短按標志
- bit flag_led_onoff;//led燈開關(guān)標志
- bit SaveFlag; //數(shù)據(jù)存儲標志
- bit flag_qh,flag_qh1;//色溫切換計時標志
- uint hcount,hcount1,hcount2;
- uchar led_qhcount;
- /////////////////////////
- void delay(uint ms)
- {
- uint i,j;
- for(i=0; i<ms; i++)
- for(j=0; j<930; j++);
- }
- //////////////////////
- /////////////////
- void IapIdle() //禁用IAP功能
- {
- IAP_CONTR = 0; //關(guān)閉IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除觸發(fā)寄存器
- IAP_ADDRH = 0x80; //將地址設(shè)置到非IAP區(qū)域
- IAP_ADDRL = 0;
- }
- char IapRead(int addr) //讀EEPROM
- {
- char dat;
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設(shè)置等待參數(shù)12MHz
- IAP_CMD = 1; //設(shè)置IAP讀命令
- IAP_ADDRL = addr; //設(shè)置IAP低地址
- IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
- _nop_();
- dat = IAP_DATA; //讀IAP數(shù)據(jù)
- IapIdle(); //關(guān)閉IAP功能
- return dat;
- }
- void IapProgram(int addr, char dat) //寫EEPROM
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設(shè)置等待參數(shù)12MHz
- IAP_CMD = 2; //設(shè)置IAP寫命令
- IAP_ADDRL = addr; //設(shè)置IAP低地址
- IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
- IAP_DATA = dat; //寫IAP數(shù)據(jù)
- IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
- _nop_();
- IapIdle(); //關(guān)閉IAP功能
- }
- void IapErase(int addr) //擦除EEPROM
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設(shè)置等待參數(shù)12MHz
- IAP_CMD = 3; //設(shè)置IAP擦除命令
- IAP_ADDRL = addr; //設(shè)置IAP低地址
- IAP_ADDRH = addr >> 8; //設(shè)置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發(fā)命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發(fā)命令(0xa5)
- _nop_(); //
- IapIdle(); //關(guān)閉IAP功能
- }
- ///////////////////
- void keyscan()
- {
- // if(tes_flag==0) //非時鐘設(shè)置狀態(tài)
- {
-
- if(k2)
- {
- k2_lock=0;
- k2_cont=0;
- if(flag_short_k2)
- {
- // cmled2=!cmled2;//按鍵指示燈取反
- flag_short_k2=0;//清零k2短按標志
- // flag_led_onoff=!flag_led_onoff;//開關(guān)燈標志取反
- flag_qh1=1;
- if(flag_qh)
- {
- flag_led_onoff=1;
- led_qhcount++;
- if(led_qhcount==3)
- {
- led_qhcount=0;
- }
- // if(led_qhcount==0) //兩路亮
- // {
- // // PWM2_Dutyv=PWM2_Dutyv>>1; //兩路都亮的亮度是一路一半的亮度
- // PWM2_Dutyv=PWM2_Dutyv/2;
- // }
- // if(led_qhcount==1)
- // {
- // // PWM2_Dutyv=PWM2_Dutyv<<1; //單路亮度是雙路亮度的2倍
- // PWM2_Dutyv=PWM2_Dutyv*2;
- // }
- // if(led_qhcount==2)
- // {
- // PWM2_Dutyv=PWM2_Dutyv;
- // }
-
- IapErase(0x1000); //擦除EEPROM
- IapProgram(0x1000, led_qhcount);//保存亮燈路數(shù)值
- hcount=0;
- hcount1=0;
- }
- else
- {
- flag_led_onoff=!flag_led_onoff;//開關(guān)燈標志取反
- }
- }
- if(SaveFlag) //長按松手后,保存pwm數(shù)據(jù)
- {
- PWM_UP_Down_Flag=!PWM_UP_Down_Flag;//調(diào)光方向標志取反
- PWM2_Dutyv_L=PWM2_Dutyv%256;//將大于255的占空比值拆分成兩個uchar的數(shù)值再保存
- PWM2_Dutyv_M=PWM2_Dutyv/256;
- IapErase(0x0001); //擦除EEPROM
- IapProgram(0x0001, PWM2_Dutyv_L);//將PWM_Value寫入EEPROM
- IapProgram(0x0002, PWM2_Dutyv_M);//將PWM_Value寫入EEPROM
- SaveFlag = 0;//保存數(shù)據(jù)后,保存標志清零
- }
-
- }
- else if(k2_lock==0) //短按
- {
- k2_cont++;
- // flag_k2=1;
- if(k2_cont>count2)
- {
- k2_cont=0;
- k2_lock=1;
- flag_short_k2=1;
- // if(flag_qh)
- // {
- // led_qhcount++;
- // if(led_qhcount==3)
- // {
- // led_qhcount=0;
- // }
- // hcount=0;
- // hcount1=0;
- // }
- }
- }
- else if(k2_cont<Long_cont2) //長按
- {
- k2_cont++;
- if(k2_cont==Long_cont2)
- {
- k2_cont=196;
- flag_short_k2=0;//進入長按必須清短按標志,否則會觸發(fā)一次短按
- SaveFlag = 1;//進入長按,保存標志置1
- if(flag_led_onoff)//開燈狀態(tài)
- {
- if(PWM_UP_Down_Flag == 1) //亮度++
- {
-
-
- // if(PWM2_Dutyv < 1023)
- // {
- // // PWM2_Dutyv +=5;
- // if(led_qhcount==0)
- // { PWM2_Dutyv +=3;
- // if(PWM2_Dutyv > 511)
- // {
- // PWM2_Dutyv = 511;
- // }
- // }
- // else
- // {
- // PWM2_Dutyv +=6;
- // if(PWM2_Dutyv > 1022)
- // {
- // PWM2_Dutyv = 1022;
- // }
- // }
- // }
- //
- // }
- //
- // if(PWM_UP_Down_Flag == 0) //亮度--
- // {
- //
- //
- // if(PWM2_Dutyv > 0)
- // {
- // if(led_qhcount==0)
- // {PWM2_Dutyv -=3;}
- // else
- // {PWM2_Dutyv -=6;}
- // if(PWM2_Dutyv < 100)
- // {
- // PWM2_Dutyv = 100;
- // }
- //
- // }
- // }
- if(PWM2_Dutyv < 1023) //亮度++
- {
- PWM2_Dutyv +=5;
- if(PWM2_Dutyv > 1022)
- {
- PWM2_Dutyv = 1022;
- }
-
- }
-
- }
-
- if(PWM_UP_Down_Flag == 0) //亮度--
- {
-
-
- if(PWM2_Dutyv > 0)
- {
- PWM2_Dutyv -=5;
- if(PWM2_Dutyv < 100)
- {
- PWM2_Dutyv = 100;
- }
-
- }
- }
-
- }
- }
-
- }
- }
- }
- //////////////////////////
- void Timer0Init(void) //2毫秒@11.0592MHz
- {
- AUXR |= 0x80; //定時器時鐘1T模式
- TMOD &= 0xF0; //設(shè)置定時器模式 16位自動重載
- TL0 = 0x9A; //設(shè)置定時初始值
- TH0 = 0xA9; //設(shè)置定時初始值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- ET0=1;
- EA=1;
- }
- //////////////////////////
- /******************** 主函數(shù) **************************/
- void main(void)
- {
- Timer0Init();
- P0M1 = 0x00; P0M0 = 0x00; //設(shè)置為準雙向口
- P1M1 = 0x00; P1M0 = 0x07; //設(shè)置為準雙向口 p12設(shè)為推挽輸出
- P2M1 = 0x00; P2M0 = 0x00; //設(shè)置為準雙向口
- P3M1 = 0x00; P3M0 = 0x00; //設(shè)置為準雙向口
- P4M1 = 0x00; P4M0 = 0x00; //設(shè)置為準雙向口
- P5M1 = 0x00; P5M0 = 0x00; //設(shè)置為準雙向口
- P6M1 = 0x00; P6M0 = 0x00; //設(shè)置為準雙向口
- P7M1 = 0x00; P7M0 = 0x00; //設(shè)置為準雙向口
- PWM1_Flag = 0;
- PWM2_Flag = 0;
- PWM3_Flag = 0;
- PWM4_Flag = 0;
-
- // PWM1_Duty = 512;
- // PWM2_Duty = 256;
- // PWM2_Dutyv=2046;
- // PWM3_Duty = 512;
- // PWM4_Duty = 1024;
-
- PWM2_Dutyv_L=IapRead(0x0001); //讀出占空比值
- PWM2_Dutyv_M=IapRead(0x0002);
- if(PWM2_Dutyv_M==255)PWM2_Dutyv_M=3; //第一次上電讀出的值是255,就給占空比賦初值
- if(PWM2_Dutyv_L==255)PWM2_Dutyv_L=255;
- //占空比最大為PWM_ARR的值
- PWM2_Dutyv=PWM2_Dutyv_M*256+PWM2_Dutyv_L;//兩個uchar合并成uint,初始最大亮度值1024
- led_qhcount=IapRead(0x1000);
- if(led_qhcount==255)led_qhcount=2;
- P_SW2 |= 0x80;
-
- PWMA_CCER1 = 0x00; //寫 CCMRx 前必須先清零 CCxE 關(guān)閉通道
- PWMA_CCER2 = 0x00;
- PWMA_CCMR1 = 0x60; //通道模式配置 設(shè)置CC1為PWMA輸出模式,方向為輸出
- PWMA_CCMR2 = 0x60;
- PWMA_CCMR3 = 0x60;
- PWMA_CCMR4 = 0x60;
- PWMA_CCER1 = 0x55; //配置通道輸出使能和極性
- PWMA_CCER2 = 0x55;
- PWMA_PSCRH = (u8)(PWM_PSCR>>8); //設(shè)置分頻
- PWMA_PSCRL = (u8)(PWM_PSCR);
- // PWMA_ARRH = (u8)(PWM_ARR >> 8); //設(shè)置周期時間
- // PWMA_ARRL = (u8)PWM_ARR;
- PWMA_ARRH = PWM_ARR/256; //設(shè)置周期時間 右移8位等同256求模
- PWMA_ARRL = PWM_ARR%256;
- /*
- 通俗的說,位移的實現(xiàn)是將數(shù)據(jù)轉(zhuǎn)換成二進制后,進行左右移動的。如果左移,則右邊補零,如果是右移,
- 則是左邊補零,后邊溢出的則去掉。因此,左移可以理解為整數(shù)的乘法,
- 而右移則是理解為整數(shù)的取整除法。
- 左移 (<<)
- 將第一個操作數(shù)向左移動第二個操作數(shù)指定的位數(shù),空出的位置補0。
- 左移相當于乘. 左移一位相當于乘2;左移兩位相當于乘4;左移三位相當于乘8。
- x<<1= x*2
- x<<2= x*4
- x<<3= x*8
- x<<4= x*16
- 同理, 右移即相反:
- 右移 (>>)
- 將第一個操作數(shù)向右移動第二個操作數(shù)所指定的位數(shù),空出的位置補0。
- 右移相當于整除. 右移一位相當于除以2;右移兩位相當于除以4;右移三位相當于除以8。
- 右移四位相當于除以16;右移8位相當于除以256.
- x>>1= x/2
- x>>2= x/4
- x>>3= x/8
- x>>4= x/16
- */
- // PWMA_ARRH = 0x03; //設(shè)置周期時間 自動重裝載高8位
- // PWMA_ARRL = 0xff;//自動重裝載低8位
- PWMA_ENO = 0x00;
- // PWMA_ENO |= ENO1P; //使能輸出
- PWMA_ENO |= ENO1N; //使能輸出
- PWMA_ENO |= ENO2P; //使能輸出
- // PWMA_ENO |= ENO2N; //使能輸出
- // PWMA_ENO |= ENO3P; //使能輸出
- // PWMA_ENO |= ENO3N; //使能輸出
- // PWMA_ENO |= ENO4P; //使能輸出
- // PWMA_ENO |= ENO4N; //使能輸出
- PWMA_PS = 0x00; //高級 PWM 通道輸出腳選擇位
- PWMA_PS |= PWM1_1; //選擇 PWM1_2 通道
- PWMA_PS |= PWM2_1; //選擇 PWM2_1 通道 p12口
- // PWMA_PS |= PWM3_3; //選擇 PWM3_3 通道
- // PWMA_PS |= PWM4_3; //選擇 PWM4_3 通道
- PWMA_BKR = 0x80; //使能主輸出
- PWMA_CR1 |= 0x01; //開始計時
- P_SW2 &= 0x7f;
- while (1)
- {
- keyscan();
- delay(4);
-
- if(flag_led_onoff==1) //開燈
- {
- switch(led_qhcount)
- {
- // case 0: PWM2_Duty = PWM2_Dutyv; PWM1_Duty = PWM2_Dutyv; break;
- //
- // case 1: PWM2_Duty = 0; PWM1_Duty = PWM2_Dutyv; break;
- //
- // case 2: PWM2_Duty = PWM2_Dutyv; PWM1_Duty = 0; break;
- case 0: PWM2_Duty = PWM2_Dutyv/2; PWM1_Duty = PWM2_Dutyv/2; break;
- case 1: PWM2_Duty = 0; PWM1_Duty = PWM2_Dutyv; break;
- case 2: PWM2_Duty = PWM2_Dutyv; PWM1_Duty = 0; break;
- default: break;
- }
- }
- else //關(guān)燈
- {
- PWM2_Duty=0;
- PWM1_Duty = 0;
- flag_qh1=0; //關(guān)燈將flag_qh1,hcount2這兩個變量清零
- hcount2=0; //否則關(guān)燈后再快速開燈會誤切換色溫
- }
-
- UpdatePwm();
-
- }
- }
- /********************** Timer0 1ms中斷函數(shù) ************************/
- void timer0(void) interrupt 1
- {
- if(flag_qh1)
- {
- hcount2++;
- if(hcount2==100)//0.2秒
- {
- hcount2=0;
- flag_qh1=0;
- flag_qh=1;
- }
- }
- if(flag_qh)
- {
- hcount++;
- if(hcount==500) //1秒
- {
- hcount=0;
- hcount1++;
- if(hcount1==3)
- {
- hcount1=0;
- flag_qh=0;
- }
- }
- }
- }
- //========================================================================
- // 函數(shù): UpdatePwm(void)
- // 描述: 更新PWM占空比.
- // 參數(shù): none.
- // 返回: none.
- // 版本: V1.0, 2012-11-22
- //========================================================================
- void UpdatePwm(void)
- {
- P_SW2 |= 0x80;
- PWMA_CCR1H = (u8)(PWM1_Duty >> 8); //設(shè)置占空比時間
- PWMA_CCR1L = (u8)(PWM1_Duty);
- PWMA_CCR2H = (u8)(PWM2_Duty >> 8); //設(shè)置占空比時間
- PWMA_CCR2L = (u8)(PWM2_Duty);
- // PWMA_CCR3H = (u8)(PWM3_Duty >> 8); //設(shè)置占空比時間
- // PWMA_CCR3L = (u8)(PWM3_Duty);
- // PWMA_CCR4H = (u8)(PWM4_Duty >> 8); //設(shè)置占空比時間
- // PWMA_CCR4L = (u8)(PWM4_Duty);
- P_SW2 &= 0x7f;
- }
復(fù)制代碼 |