基于STC8G的可调节占空比和频率的PWM应用案例
CSDN的小白分享
前言
学习单片机以来,都是写了就算的态度。总结的话用TXT和WPS文档老是容易忘掉放在了哪里。而且排版也不好看,无意间发现了可以在这里面做记录,于是就开始了啦!
由于工程需要(三色灯切换同时呼吸效果),最近在研究一款比较合适用来做面板LED控制的小成本芯片:以下就是STC8G1K08A系列的开发记录,实现了可调频调占空比的PWM输出。
一、STC8G系列的介绍
STC8G是STC公司最近新出的一款产品,它性价比高,内存充足等特点,主要是价格适合,功能足,可以满足各种扩展需要。至于其他内容可以上官网自己查看,不然就有卖广告的嫌疑了~
二、使用记录
1.建立工程
本人是在KEIL中进行开发的,所以使用前需要先在STC官网下载以下它的最新ISP软件,然后在软件把最新的STC8G系列的头文件加到KEIL的INC文件夹中。
2.打开工程所需的芯片功能,及本人的函数
1.主程序中断函数如下:
//定时器0中断----------------------------------------------------------------------------------------
void Time0() interrupt 1
{
WDT_CONTR=0x30;
Time_Cnt();
}
void main()
{
Port_Init();
EA = 0;
Delay_Us(1);
Delay_N_Ms(1);
Timer0_Init();
Delay_N_Ms(10);
PWM_Init();
PWM_Off();
Delay_N_Ms(10);
Data_Init();
EA = 1;
while(1)
{
On_Off_Chk();
Led_Control();
}
}
2.初始化函数:
void Port_Init(void)//根据芯片引脚定义,把PWM的输出脚定义为推挽输出
{
P3M1 = 0xF3;//1111 0011
P3M0 = 0x0C;//0000 1100
P5M1 = 0xEF;//1110 1111
P5M0 = 0x10;//0001 0000
}
//定时器0初始化--------------------------------------------------------------------------------------
void Timer0_Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
PT0 = 0; //定时器0优先级置低
}
void PWM_Init(void)
{
CCON = 0x00;
CMOD = 0x08; //PCA时钟为系统时钟
CL = 0x00; //PCA计数器初始值低8位
CH = 0x00; //PCA计数器初始值高8位
CCAPM0 = 0x42; //PCA模块1为PWM工作模式
PCA_PWM0 = 0xc0; //PCA模块1输出10位PWM
CCAP0L = 0x00;
CCAP0H = 0x00;
CCAPM1 = 0x42; //PCA模块1为PWM工作模式
PCA_PWM1 = 0xc0; //PCA模块1输出10位PWM
CCAP1L = 0x00;
CCAP1H = 0x00;
CCAPM2 = 0x42; //PCA模块1为PWM工作模式
PCA_PWM2 = 0xc0; //PCA模块1输出10位PWM
CCAP2L = 0x00;
CCAP2H = 0x00;
CR = 1; //启动PCA计时器
}
void Data_Init(void)
{
setPWM = 1023;
chaSynFlag = 0;
ledUpdateColorFlag = 0;
ledKeepOffFlag = 0;
pwmUpdateFlag = 0;
switchOnFlag = 0;
countBreNMs = 0;
countOffNMs = 0;
}
3.为了简化输出和方便以后修改做的自定义函数封装:
void Time_Cnt(void)//程序主要时间逻辑计算函数
{
countBreNMs++;
if(countBreNMs >= PWM_BREATHE_NS)
{
pwmUpdateFlag = 1;
countBreNMs = 0;
}
count20Ms++;
if(count20Ms >= 10)
{
count20Ms = 0;
count1S++;
if(count1S >= 200)
{
count1S = 0;
countOffNMs ++;
countHoldNMs++;
if(countOffNMs >= PWM_OFF_TIME)
{
countOffNMs = 0;
ledKeepOffFlag = 0;
}
else if(countHoldNMs >= PWM_HOLD_TIME)
{
countHoldNMs = 0;
ledKeepHoldFlag = 0;
}
}
}
}
void PWM_Output_Capp0(void)
{
PCA_PWM0=0x30&(setPWM>>4)|0xc0;//高两位XCCAPnH[1:0]
CCAP0H = setPWM;//低8位CCAPnH[7:0]
}
void PWM_Output_Capp1(void)
{
PCA_PWM1=0x30&(setPWM>>4)|0xc0;//高两位XCCAPnH[1:0]
CCAP1H = setPWM;//低8位CCAPnH[7:0]
}
void PWM_Output_Capp2(void)
{
PCA_PWM2=0x30&(setPWM>>4)|0xc0;//高两位XCCAPnH[1:0]
CCAP2H = setPWM;//低8位CCAPnH[7:0]
}
void PWM_Off(void)
{
PCA_PWM0|=0x3F;//高两位XCCAPnH[1:0]
CCAP0H = 0XFF;//低8位CCAPnH[7:0]
PCA_PWM1|=0x3F;//高两位XCCAPnH[1:0]
CCAP1H = 0XFF;//低8位CCAPnH[7:0]
PCA_PWM2|=0x3F;//高两位XCCAPnH[1:0]
CCAP2H = 0XFF;//低8位CCAPnH[7:0]
}
void PWM_On(void)
{
if(chaSynFlag)
{
if(!ledKeepHoldFlag)
{
setPWM ++;
if(setPWM == 1023)
{
chaSynFlag = 0;
ledUpdateColorFlag = 1;
ledKeepOffFlag = 1;
}
}
}
else
{
setPWM --;
if(setPWM == 0)
{
chaSynFlag = 1;
ledKeepHoldFlag = 1;
countHoldNMs = 0;
}
}
Led_Select();
}
void Led_Control(void)
{
if((!ledKeepOffFlag)&&(switchOnFlag))
{
if(pwmUpdateFlag)
{
PWM_On();
pwmUpdateFlag = 0;
countOffNMs = 0;
}
}
else
{
PWM_Off();
countBreNMs = 0;
}
}
void On_Off_Chk(void)
{
if(!ON_OFF_SW)
switchOnFlag = 1;
else
{
setPWM = 1023;
chaSynFlag = 0;
ledUpdateColorFlag = 0;
ledKeepOffFlag = 0;
pwmUpdateFlag = 0;
switchOnFlag = 0;
countBreNMs = 0;
countOffNMs = 0;
switchOnFlag = 0;
}
}
void Led_Select(void)
{
if(ledUpdateColorFlag)
{
ledUpdateColorFlag = 0;
ledSelectCnt ++;
if(ledSelectCnt >= 35)
{
ledSelectCnt = 0;
}
ledSrlectData = ledBuf[ledSelectCnt];
}
if(ledSrlectData == 0)
PWM_Output_Capp0();
else if(ledSrlectData ==1)
PWM_Output_Capp1();
else if(ledSrlectData == 2)
PWM_Output_Capp2();
else if(ledSrlectData == 3)
{
PWM_Output_Capp0();
PWM_Output_Capp1();
}
else if(ledSrlectData == 4)
{
PWM_Output_Capp1();
PWM_Output_Capp2();
}
else if(ledSrlectData == 5)
{
PWM_Output_Capp0();
PWM_Output_Capp2();
}
else if(ledSrlectData == 6)
{
PWM_Output_Capp0();
PWM_Output_Capp1();
PWM_Output_Capp2();
}
}
4.在头文件中进行变量定义和宏定义即可方便的调节呼吸和变色效果:
sbit ON_OFF_SW = P5^5;
#define MAIN_Fosc 24000000L //定义主时钟
#define PWM_BREATHE_NS 5 //一次呼吸的时间
#define PWM_OFF_TIME 3 //每次停顿的时间
#define PWM_HOLD_TIME 3 //最亮停顿的时间
//screen
bit ledUpdateColorFlag=0;
bit ledKeepHoldFlag=0;
bit ledKeepOffFlag=0;
bit pwmUpdateFlag=0;
bit switchOnFlag=0;
bit chaSynFlag = 0;
u8 ledSrlectData=0;
u8 ledSelectCnt=0;
u16 setPWM=0;//10位占空比预存变量0-1023
u8 code ledBuf[35] =
{
0,1,2,3,4,5,6,
4,3,1,5,0,6,2,
1,2,4,6,5,0,3,
6,5,4,3,2,1,0,
4,3,2,6,2,0,1
};//添加该数组目的是让灯的颜色变的随机(伪随机),可以适当的增加但同时对应的选择变量也要更改条件
//Timer
u8 countBreNMs;
u8 countOffNMs;
u8 countHoldNMs;
u8 count20Ms;
u8 count1S;
总结
以上是这次工程的全部函数代码,至于一些基本的头文件这里就不一一的细讲了。工程实现了可调节呼吸频率,呼吸时间的三色灯。
小白一个,期待各位大佬多多指教。同时也希望自己能保持每个工程都编写文章以做记录和反省!