打印
[STC单片机]

基于stc12c5a60s2的呼吸灯设计

[复制链接]
1664|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
蔬木果|  楼主 | 2018-6-24 22:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我在用stc12c5a60s2做呼吸灯设计时遇到的问题,我想设计出几路频率变化不一样的pwm波形,我第一个是利用了C51里面的两个计数器实现了呼吸灯设计,可以使三个灯做相同频率的呼吸,代码如下://实现三个灯的呼吸#include <reg52.h>

sbit PWMOUT0 = P0^0;
sbit PWMOUT1 = P0^1;
sbit PWMOUT2 = P0^2;

unsigned char HighRH = 0;  //高电平重载值的高字节
unsigned char HighRL = 0;  //高电平重载值的低字节
unsigned char LowRH  = 0;  //低电平重载值的高字节
unsigned char LowRL  = 0;  //低电平重载值的低字节
unsigned char T1RH = 0;
unsigned char T1RL = 0;
unsigned long PeriodCnt = 0;

void ConfigTimer1(unsigned int ms);
void ConfigPWM(unsigned int fr, unsigned char dc);

void main()
{
    EA = 1;     //开定时器总中断

    ConfigPWM(100, 10);  //配置并启动PWM
    ConfigTimer1(50);    //用T1定时调整占空比
    while (1);
}
void ConfigTimer1(unsigned int ms)
{
    unsigned long tmp;  //临时变量

    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T1RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T1RL = (unsigned char)tmp;
    TMOD &= 0x0F;   //清零T1的控制位
    TMOD |= 0x10;   //配置T1为模式1
    TH1 = T1RH;     //加载T1重载值
    TL1 = T1RL;
    ET1 = 1;        //使能T1中断
    TR1 = 1;        //启动T1
}
void ConfigPWM(unsigned int fr, unsigned char dc)
{
    unsigned int high, low;

    PeriodCnt = (11059200/12) / fr; //计算一个周期所需的计数值
    high = (PeriodCnt*dc) / 100;    //计算高电平所需的计数值
    low  = PeriodCnt - high;        //计算低电平所需的计数值
    high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
    low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
    HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
    HighRL = (unsigned char)high;
    LowRH  = (unsigned char)(low>>8);  //低电平重载值拆分为高低字节
    LowRL  = (unsigned char)low;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = HighRH;   //加载T0重载值
    TL0 = HighRL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    PWMOUT0 = 1;     //输出高电平
        PWMOUT1 = 1;     //输出高电平
        PWMOUT2 = 1;     //输出高电平
}
void AdjustDutyCycle(unsigned char dc)          //调整占空比
{
        unsigned int high, low;

        high = (PeriodCnt*dc)/100;
        low = PeriodCnt - high;
        high = 65536 - high + 12;
        low = 65536 - low + 12;
        HighRH = (unsigned char)(high >> 8);
        HighRL = (unsigned char)high;
        LowRH = (unsigned char)(low >> 8);
        LowRL = (unsigned char)low;
}
void InterruptTimer0() interrupt 1                        //用定时器0,实现了灯的亮灭连续变化,实现电平的反转
{
    if (PWMOUT0 == 1)  //当前输出为高电平时,装载低电平值并输出低电平
    {
        TH0 = LowRH;
        TL0 = LowRL;
        PWMOUT0 = 0;
                PWMOUT1 = 0;     
            PWMOUT2 = 0;     
    }
    else              //当前输出为低电平时,装载高电平值并输出高电平
    {
        TH0 = HighRH;
        TL0 = HighRL;
        PWMOUT0 = 1;
        PWMOUT1 = 1;     
        PWMOUT2 = 1;
    }
}

void InterruptTimer1() interrupt 3
{
        unsigned char code table[13] = {
        5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95
        };
        static bit dir = 0;
        static unsigned char index = 0;

        TH1 = T1RH;
        TL1 = T1RL;

        AdjustDutyCycle(table[index]);
        if(dir == 0)
        {
                index++;
                if(index >= 12)
                {
                        dir = 1;
                }
        }
        else
        {
                index--;
                if(index == 0)
                {
                        dir = 0;
                }
        }
}
可是,我并不想看到一样的频率变化,我希望三个灯变化的频率不一样,可是上述代码实现呼吸灯的效果是基于计数器的个数的,C51的计数器已经用完了,我只好把目光投向了stc12c5a60s,这里面不仅有四个计数器,而且有两路PWM输出,我通过设置PCA,实现了通过按键可以实时改变输出波形,代码如下:
//利用按键s1对led灯的亮度调节
#include"STC12C5A60S2.h"

void delay(unsigned int cnt)
{
unsigned char i;
for(;cnt>0;cnt--)
for(i=0;i<250;i++);
}

void main()
{
EA = 1;     //开定时器总中断

CCON=0;                 //禁止寄存器CCON中CF位的中断
CL=0;                 //PCA的16位计数器低8位
CH=0;                 //PCA的16位计数器高8位
CMOD=0x00;         //选择系统时钟/12为计数脉冲,则PWM的频率f=sysclk/256/12

//PCA模块0
CCAP0H=0x80; //占空比控制,此时的占空比为50%,一路输出
CCAP0L=0x80;
PCA_PWM0=0x00; //控制占空比的第九位为0
CCAPM0=0x42;   //允许P13作为PWM输出

//PCA模块1
CCAP1H=0xcc;  //占空比控制,此时的占空比为20%,一路输出
CCAP1L=0xcc;
PCA_PWM1=0x00;
CCAPM1=0x42;  //允许P13作为PWM输出

CR=1;                   //启动PCA计数器

while(1)
{

if(P10==0)
{
delay(200);
while(P10==0);
CCAP0H+=10;           //占空比调节
CCAP0L+=10;

CCAP1H+=25;           //占空比调节
CCAP1L+=25;
}
}
}

可是就在我想结合两者的特点一起实现三个灯做呼吸灯,另外两个灯通过按键做使其的波形不断变化,因为这在设计上我觉得是行得通的,因为我做呼吸灯时,只涉及到51的定时器,而stc12c5a60s2很好的兼容了51的两个定时器,这样的话,应该是可以同时出现三个灯是呼吸灯,最后两个灯通过按键调节亮度,所以我就把两个函数粘贴在一起了,可是却没有出现应有的现象。
问题如下:只能通过按键对最后两个灯实现亮度调节,而呼吸灯的现象出不来。
有问题的程序如下,不知道怎样修改,还请大神解惑。
//利用按键s1对led灯的亮度调节
#include"STC12C5A60S2.h"

sbit PWMOUT0 = P0^0;
sbit PWMOUT1 = P0^1;
sbit PWMOUT2 = P0^2;

unsigned char HighRH = 0;  //高电平重载值的高字节
unsigned char HighRL = 0;  //高电平重载值的低字节
unsigned char LowRH  = 0;  //低电平重载值的高字节
unsigned char LowRL  = 0;  //低电平重载值的低字节
unsigned char T1RH = 0;
unsigned char T1RL = 0;
unsigned long PeriodCnt = 0;

void ConfigTimer1(unsigned int ms);
void ConfigPWM(unsigned int fr, unsigned char dc);

void delay(unsigned int cnt)
{
unsigned char i;
for(;cnt>0;cnt--)
for(i=0;i<250;i++);
}

void main()
{
EA = 1;     //开定时器总中断

CCON=0;                 //禁止寄存器CCON中CF位的中断
CL=0;                 //PCA的16位计数器低8位
CH=0;                 //PCA的16位计数器高8位
CMOD=0x00;         //选择系统时钟/12为计数脉冲,则PWM的频率f=sysclk/256/12

//PCA模块0
CCAP0H=0x80; //占空比控制,此时的占空比为50%,一路输出
CCAP0L=0x80;
PCA_PWM0=0x00; //控制占空比的第九位为0
CCAPM0=0x42;   //允许P13作为PWM输出

//PCA模块1
CCAP1H=0xcc;  //占空比控制,此时的占空比为80%,一路输出
CCAP1L=0xcc;
PCA_PWM1=0x00;
CCAPM1=0x42;  //允许P13作为PWM输出

CR=1;                   //启动PCA计数器

while(1)
{
    ConfigPWM(100, 10);  //配置并启动PWM
    ConfigTimer1(50);    //用T1定时调整占空比
if(P10==0)
{
delay(200);
while(P10==0);
CCAP0H+=10;           //占空比调节
CCAP0L+=10;

CCAP1H+=25;           //占空比调节
CCAP1L+=25;
}
}
}

void ConfigTimer1(unsigned int ms)
{
    unsigned long tmp;  //临时变量

    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T1RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T1RL = (unsigned char)tmp;
    TMOD &= 0x0F;   //清零T1的控制位
    TMOD |= 0x10;   //配置T1为模式1
    TH1 = T1RH;     //加载T1重载值
    TL1 = T1RL;
    ET1 = 1;        //使能T1中断
    TR1 = 1;        //启动T1
}
void ConfigPWM(unsigned int fr, unsigned char dc)
{
    unsigned int high, low;

    PeriodCnt = (11059200/12) / fr; //计算一个周期所需的计数值
    high = (PeriodCnt*dc) / 100;    //计算高电平所需的计数值
    low  = PeriodCnt - high;        //计算低电平所需的计数值
    high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
    low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
    HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
    HighRL = (unsigned char)high;
    LowRH  = (unsigned char)(low>>8);  //低电平重载值拆分为高低字节
    LowRL  = (unsigned char)low;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = HighRH;   //加载T0重载值
    TL0 = HighRL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
    PWMOUT0 = 1;     //输出高电平
        PWMOUT1 = 1;     //输出高电平
        PWMOUT2 = 1;     //输出高电平
}
void AdjustDutyCycle(unsigned char dc)          //调整占空比
{
        unsigned int high, low;

        high = (PeriodCnt*dc)/100;
        low = PeriodCnt - high;
        high = 65536 - high + 12;
        low = 65536 - low + 12;
        HighRH = (unsigned char)(high >> 8);
        HighRL = (unsigned char)high;
        LowRH = (unsigned char)(low >> 8);
        LowRL = (unsigned char)low;
}
void InterruptTimer0() interrupt 1                        //用定时器0,实现了灯的亮灭连续变化,实现电平的反转
{
    if (PWMOUT0 == 1)  //当前输出为高电平时,装载低电平值并输出低电平
    {
        TH0 = LowRH;
        TL0 = LowRL;
        PWMOUT0 = 0;
                PWMOUT1 = 0;     
            PWMOUT2 = 0;     
    }
    else              //当前输出为低电平时,装载高电平值并输出高电平
    {
        TH0 = HighRH;
        TL0 = HighRL;
        PWMOUT0 = 1;
        PWMOUT1 = 1;     
            PWMOUT2 = 1;
    }
}

void InterruptTimer1() interrupt 3
{
        unsigned char code table[13] = {
        5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95
        };
        static bit dir = 0;
        static unsigned char index = 0;

        TH1 = T1RH;
        TL1 = T1RL;

        AdjustDutyCycle(table[index]);
        if(dir == 0)
        {
                index++;
                if(index >= 12)
                {
                        dir = 1;
                }
        }
        else
        {
                index--;
                if(index == 0)
                {
                        dir = 0;
                }
        }
}



相关帖子

沙发
owencai| | 2018-9-25 09:35 | 只看该作者
学习学习

使用特权

评论回复
板凳
tianxiongweitxw| | 2018-9-25 13:53 | 只看该作者
一定要用硬件计数器吗,要求不高应该可以用软件计数器啊,可以做无时个定时器,计数器。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

171

帖子

2

粉丝