找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2363|回复: 12
打印 上一主题 下一主题
收起左侧

STC15W408AS单片机系列通过I/O设置PWM输出(不是使用PWM功能)程序有没有第二种思路?

[复制链接]
跳转到指定楼层
楼主
单片机芯片使用STC15W408AS,由于PWM端数量只有3路,但实际使用到需要4路,为方便使用编写一段PWM,占空比是1/3,向大家分享下。

想了很久,自己思维定式,向大家请教,有没有另外一种更简洁的方案,并且能使PWM占空比是1:4(开:关),占空比的波形尽量小,谢谢大家,我继续思考中

单片机源程序如下,给大家分享看
u16 xdata JS1=0;  //计时时间
u16 xdata JS2=0;  //计时时间
u16 xdata JS3=0;  //计时时间
u16 xdata JS4=0;  //计时时间
u16 xdata JS11=0;  //计时时间
u16 xdata JS22=0;  //计时时间
u16 xdata JS33=0;  //计时时间
u16 xdata JS44=0;  //计时时间
u16 xdata JS111=0;  //计时时间
u16 xdata JS222=0;  //计时时间
u16 xdata JS333=0;  //计时时间
u16 xdata JS444=0;  //计时时间
u16 xdata QD1=60;    //启动阀的时间
u16 xdata QD2=61;    //启动阀的时间
u16 xdata GB1=20;    //关闭延时
bit bdata IN1_BZ=0;
bit bdata IN2_BZ=0;
bit bdata IN3_BZ=0;
bit bdata IN4_BZ=0;

u16 xdata time_cnt;
bit bdata FZ_BZ=0;

void T0_Init(void)    //T0初始化 60μS 11.0592
{
        AUXR |= 0x80;        //设置为1T工作模式
        TMOD &= 0xF0;        //设置定时器模式
        TL0 = 0x68;        //设置定时初始值
        TH0 = 0xFD;        //设置定时初始值
        TF0 = 0;                //清除TF0
        TR0 = 1;                //定时器0启动
        ET0=1;      //T0开
        EA=1;        //总中断开
}
void T0_ZD(void) interrupt 1  //
{  
                time_cnt++;
                if(time_cnt<1000)
                {
                        FZ_BZ=0;
                }
                else if(time_cnt<2000)
                {
                        FZ_BZ=1;
                }
                else
                {
                        time_cnt=0;
                }
    if(FZ_BZ==0) //判断是否有输入信号
          {
                  JS111=0;
                  JS1++;
                          IN1_BZ=1;
                        if(JS1<=QD1)        //直接给电
                  {
                          OUT1=0;   //开阀
                  }
                  else                        //进入pwm
                  {
                          JS1=QD2;
                          JS11++;
                          if(JS11<=1)//直接给电
                          {
                                  OUT1=0;   //开阀
                          }
                          else                //不给电
                          {
                                 if(JS11==3)
                                 {
                                         JS11 = 0;        //置0
                                 }
                                 OUT1=1;   //关阀
                          }
                        }
                }  
          else
          {
                        JS111++;
                        if(JS111<GB1)//
                        {
                                OUT1=0;
                        }
                        else
                        {
                                OUT1=1;
                                JS1=0;
                                IN1_BZ=0;
                        }
          }
//***************************************************************************        
if(FZ_BZ==0) //判断是否有输入信号
          {
                  JS222=0;
                  JS2++;
                  IN2_BZ=1;
                if(JS2<=QD1)        //直接给电
                  {
                          OUT2=0;   //开阀
                  }
                  else                        //进入pwm
                  {
                          JS2=QD2;
                          JS22++;
                          if(JS22<=1)//直接给电
                          {
                                  OUT2=0;   //开阀
                          }
                          else                //不给电
                          {
                                 if(JS22==3)
                                 {
                                         JS22 = 0;        //置0
                                 }
                                 OUT2=1;   //关阀
                          }
                        }
                }  
          else
          {
                        JS222++;
                        if(JS222<GB1)
                        {
                         OUT2=0;
                        }
                        else
                        {
                                OUT2=1;
                                JS2=0;
                                IN2_BZ=0;
                        }
         }        
//***********************************************************************
if(FZ_BZ==0) //判断是否有输入信号
          {   
                  JS333=0;
                  JS3++;
                  IN3_BZ=1;
                if(JS3<=QD1)        //直接给电
                  {
                          OUT3=0;   //开阀
                  }
                  else                        //进入pwm
                  {
                           JS3=QD2;
                          JS33++;
                          if(JS33<=1)//直接给电
                          {
                                  OUT3=0;   //开阀
                          }
                          else                //不给电
                          {
                                 if(JS33==3)
                                 {
                                         JS33 = 0;        //置0
                                 }
                                 OUT3=1;   //关阀
                          }
                        }
                }  
          else
          {
                        JS333++;
                        if(JS333<GB1)
                        {
                         OUT3=0;
                        }
                        else
                        {
                                OUT3=1;
                                JS3=0;
                                IN3_BZ=0;
                        }
         }        
//************************************************************
if(FZ_BZ==0) //判断是否有输入信号
          {
                  JS444=0;
                  JS4++;
                  IN4_BZ=1;
                        if(JS4<=QD1)        //直接给电
                  {
                          OUT4=0;   //开阀
                  }
                  else                        //进入pwm
                  {
                           JS4=QD2;
                          JS44++;
                          if(JS44<=1)//直接给电
                          {
                                  OUT4=0;   //开阀
                          }
                          else                //不给电
                          {
                                 if(JS44==3)
                                 {
                                         JS44 = 0;        //置0
                                 }
                                 OUT4=4;   //关阀
                                }
                        }
                }  
          else
          {
                        JS444++;
                        if(JS444<GB1)
                        {
                         OUT4=0;
                        }
                        else
                        {
                                OUT4=1;
                                JS4=0;
                                IN4_BZ=0;
                        }
                }
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:161164 发表于 2022-5-26 00:33 | 只看该作者
用xdata来运算是很耗时的经仿真,你的中断最少用44us,最多用87us,
已经超过中断时间了



把所有xdata改回普通data,耗时立刻减少,
但PWM写法还是有点累赘



用简洁一点的写法大大减少中断耗时



回复

使用道具 举报

板凳
ID:1029559 发表于 2022-5-26 08:40 | 只看该作者
lkc8210 发表于 2022-5-26 00:33
用xdata来运算是很耗时的经仿真,你的中断最少用44us,最多用87us,
已经超过中断时间了

感谢指教,确实减少了许多,中断时间加快了,那后面PWM用while?
回复

使用道具 举报

地板
ID:339654 发表于 2022-5-26 08:52 | 只看该作者
可以用定时器模拟一路PWM
回复

使用道具 举报

5#
ID:390416 发表于 2022-5-26 09:35 | 只看该作者
u8 idata PWM_Write_Byte[4]=0;                                // 占空比
#define FOSC 30000000UL                                                // 声明系统频率,30M,要与STC-ISP同步设置
#define PWM_F 1000                                                        // 设置PWM频率,不宜太高。
#define PWM_D 255                                                        // 设置占空阈值,必须大于占空比的最大值,并且小于256
#define PWM_TL (256-(FOSC/12/PWM_F/PWM_D))        // 计算定时器初值(8位)

// 定时器0初始化  
void PWM_Init()
{
        TMOD &= 0xF0;                                  //配置定时器工作模式
        TMOD |= 0x02;                                          //配置定时器工作模式 8位自动重装模式
    TL0 = PWM_TL;                                    //定时器初值
    TH0 = PWM_TL;                                    //定时器重装初值
    TR0 = 1;                                        //启动定时器0
    ET0=1;                                  //允许定时器0申请中断
    EA=1;                                   //中断总闸闭合
}

//定时器0的CPU处理函数,位置任意写都行
void PWM_Display_timer0() interrupt 1
{
        static u8 pwm_t=0;                        //局部变量,不丢失数据
               
                if(pwm_t<PWM_Write_Byte[2])
        {
                        PWM_GPIO_G=0;                                  //绿                       
        }
        else PWM_GPIO_G=1;
        pwm_t++;
                pwm_t=pwm_t%PWM_D;                                        //限制占空比小于占空阈值
}
回复

使用道具 举报

6#
ID:161164 发表于 2022-5-26 10:47 来自手机 | 只看该作者
xjin1989 发表于 2022-5-26 08:40
感谢指教,确实减少了许多,中断时间加快了,那后面PWM用while?

什么叫"那后面PWM用while?"
回复

使用道具 举报

7#
ID:1029559 发表于 2022-5-26 10:57 | 只看该作者
weijoyer 发表于 2022-5-26 08:52
可以用定时器模拟一路PWM

这是个方案,但定时器有其他功能占用了,需要用普通I/O口来模拟PWM信号
回复

使用道具 举报

8#
ID:1029559 发表于 2022-5-26 11:00 | 只看该作者
lkc8210 发表于 2022-5-26 10:47
什么叫"那后面PWM用while?"

老师,我是看到你最后用了while,你看哈
void main()
{
     T0_Init();
     while(1);
}
你前面是设置开关的时间占比吧,后面就是用while循环反复吧
回复

使用道具 举报

9#
ID:1029559 发表于 2022-5-26 11:02 | 只看该作者
人人学会单片机 发表于 2022-5-26 09:35
u8 idata PWM_Write_Byte[4]=0;                                // 占空比
#define FOSC 30000000UL                                                // 声明系统频率,30M,要与S ...

这是用到的PWM口吧
回复

使用道具 举报

10#
ID:624769 发表于 2022-5-26 22:00 | 只看该作者
本帖最后由 188610329 于 2022-5-26 22:01 编辑

既然,你只需要4路PWM, 既然你单片机本来就有 3路PWM,  那么你定时器只需要 模拟一路PWM即可,那么完全不用那么频繁的中断定时器,直接利用定时器的自动重载功能,可以做到 模拟出MHz级别的 PWM,占用资源还少……。

#include <STC15F2K60S2.H>

//============ 手动设置部分  ===============
#define        Mainforse                33177600L        //晶振频率(Hz)
#define        Pulse_frequency                420                //脉冲频率(Hz)        即一秒钟发生多少个脉冲。
#define        Pulse_High                1                //高电平占比        占空比为(Pulse_High/(Pulse_High + Pulse_Low))
#define        Pulse_Low                4                //低电平占比
sbit        PWMIO = P2^0;
//============ 手动设置部分  ===============

//============        自动设置部分 ===============
#define        Pulse_Count_High        (Mainforse * Pulse_High / Pulse_frequency /(Pulse_High + Pulse_Low))
#define        Pulse_Count_Low                (Mainforse * Pulse_Low / Pulse_frequency /(Pulse_High + Pulse_Low))
#if        ((Pulse_Count_High  < 65536) && (Pulse_Count_Low  < 65536))
        #define        SET_T0_CLK()        AUXR        |= 0x80
        #define        Reload_High        (65536 - Pulse_Count_High)
        #define        Reload_Low        (65536 - Pulse_Count_Low)
#else
        #define        SET_T0_CLK()        AUXR        &= 0x7f
        #define        Reload_High        (65536 - (Pulse_Count_High / 12))
        #define        Reload_Low        (65536 - (Pulse_Count_Low / 12))
#endif
//============        自动设置部分 ===============


void        Main()
{
        SET_T0_CLK();
        TMOD        = 0x00;                        //16位自动重载模式
        TH0        = Reload_High / 256;        //给高电平计数值
        TL0        = Reload_High % 256;
        TR0        = 1;
        PT0        = 1;
        ET0        = 1;
        EA        = 1;
        PWMIO        = 1;                        //IO给高电平
        TH0        = Reload_Low / 256;        //给低电平计数值
        TL0        = Reload_Low % 256;
        while(1);
}

void        T0_INT()        interrupt 1
{
        if(PWMIO)
        {
                PWMIO        = 0;
                TH0        = Reload_High / 256;
                TL0        = Reload_High % 256;
        }
        else
        {
                PWMIO        = 1;
                TH0        = Reload_Low / 256;
                TL0        = Reload_Low % 256;
        }
}

回复

使用道具 举报

11#
ID:161164 发表于 2022-5-26 22:49 来自手机 | 只看该作者
xjin1989 发表于 2022-5-26 11:00
老师,我是看到你最后用了while,你看哈
void main()
{

老师不敢当,互相交流
那是因为看不懂中断里的部分代表
就不写了
直接弄个while(1)
回复

使用道具 举报

12#
ID:1029559 发表于 2022-5-27 13:26 | 只看该作者
188610329 发表于 2022-5-26 22:00
既然,你只需要4路PWM, 既然你单片机本来就有 3路PWM,  那么你定时器只需要 模拟一路PWM即可,那么完全不用 ...

对哦,我是可以三路PWM的换到其他地方去
回复

使用道具 举报

13#
ID:1029559 发表于 2022-5-27 13:27 | 只看该作者
人人学会单片机 发表于 2022-5-26 09:35
u8 idata PWM_Write_Byte[4]=0;                                // 占空比
#define FOSC 30000000UL                                                // 声明系统频率,30M,要与S ...

打开新的窗口啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表