找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2014|回复: 6
收起左侧

STC8A单片机输出任意路(8路以内)同频率同占空比不同相位的pwm波怎么实现啊?求指点

[复制链接]
回帖奖励 5 黑币 回复本帖可获得 5 黑币奖励! 每人限 1 次
ID:1005634 发表于 2022-10-26 22:17 | 显示全部楼层 |阅读模式
用定时器1查询延时和中断延时都试过了,示波器上显示的都是相位一样的PWM波。求大神指点。每路的相位差值是打算弄成(一个周期的时间/pwm路数)。
PWM波是直接用STC8A上pwm寄存器生成的代码如下(这个生成pwm波应该没有问题示波器上显示是正确的):
void PWM_init(int pin,long f,int pwm)  //PWM初始化函数
{
        switch(pin%10)
        {
                case 0:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==10) PWM0CR=0x08;
                        if(pin==20) PWM0CR=0x00;
                        if(pin==60) PWM0CR=0x10;
                        PWM0_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数(精度)
                        PWMC = PWM0_T;                        //设置PWM周期时钟数
                        PWM0T1= (long)pwm*PWM0_T/10000;              //PWM0在计数值为15000地方输出低电平
                        PWM0T2= 0;                             //PWM0在计数值为0地方输出高电平                        
                        PWM0CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 1:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==11) PWM1CR=0x08;
                        if(pin==21) PWM1CR=0x00;
                        if(pin==61) PWM1CR=0x10;
                        PWM1_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM1_T;                        //设置PWM周期时钟数
                        PWM1T1= (long)pwm*PWM1_T/10000;              //PWM1在计数值为100H地方输出低电平
                        PWM1T2= 0;                             //PWM1在计数值为700H地方输出高电平                        
                        PWM1CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM1
                }
                case 2:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==12) PWM2CR=0x08;
                        if(pin==22) PWM2CR=0x00;
                        if(pin==62) PWM2CR=0x10;
                        PWM2_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM2_T;                        //设置PWM周期时钟数
                        PWM2T1= (long)pwm*PWM2_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM2T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM2CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 3:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==13) PWM3CR=0x08;
                        if(pin==23) PWM3CR=0x00;
                        if(pin==63) PWM3CR=0x10;
                        PWM3_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM3_T;                        //设置PWM周期时钟数
                        PWM3T1= (long)pwm*PWM3_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM3T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM3CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 4:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==14) PWM4CR=0x08;
                        if(pin==24) PWM4CR=0x00;
                        if(pin==64) PWM4CR=0x10;
                        PWM4_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM4_T;                        //设置PWM周期时钟数
                        PWM4T1= (long)pwm*PWM4_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM4T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM4CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 5:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==15) PWM5CR=0x08;
                        if(pin==25) PWM5CR=0x00;
                        if(pin==65) PWM5CR=0x10;
                        PWM5_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM0_T;                        //设置PWM周期时钟数
                        PWM5T1= (long)pwm*PWM5_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM5T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM5CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 6:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==16) PWM6CR=0x08;
                        if(pin==26) PWM6CR=0x00;
                        if(pin==66) PWM6CR=0x10;
                        PWM6_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM6_T;                        //设置PWM周期时钟数
                        PWM6T1= (long)pwm*PWM6_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM6T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM6CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
                case 7:
                {
                        //STORE=P_SW2;
                        P_SW2 |= 0x80; //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1                        
                        PWMCKS = 0x0f;                              // PWM时钟为系统时钟/16 ,以适应不同PWM频率。   
                        PWMCFG = 0x00;                                                                                          //PWM配置寄存器,PWM无中断,PWM不与ADC关联
                        if(pin==17) PWM7CR=0x08;
                        if(pin==27) PWM7CR=0x00;
                        if(pin==67) PWM7CR=0x10;
                        PWM7_T = Main_Fosc16/f;                   //计算PWM一个周期总脉冲数
                        PWMC = PWM7_T;                        //设置PWM周期时钟数
                        PWM7T1= (long)pwm*PWM7_T/10000;              //PWM0在计数值为100H地方输出低电平
                        PWM7T2= 0;                             //PWM0在计数值为700H地方输出高电平                        
                        PWM7CR|=0x80;                          //使能PWM输出
                        P_SW2  &= ~0x80;                       //PSW2寄存器最高位清0   
                        PWMCR  |= 0x80;   //使能PWM波形发生器,PWM计数器开始工作
                        break;   //PWM0
                }
        }        
}void PWM_change(int pin,int pwm)    //改变PWM模块占空比
{
        //STORE=P_SW2;
        P_SW2 |= 0x80;  //以下寄存器为扩展sfr,访问前需先将PSW2寄存器最高位置1        
        switch(pin%10)
        {
                case 0:        PWM0T1= (long)pwm*PWM0_T/10000;        //PWM0在计数值为100H地方输出低电平
                                                break;
                case 1:        PWM1T1= (long)pwm*PWM1_T/10000;        //PWM1在计数值为100H地方输出低电平                                       
                                                break;
                case 2:        PWM2T1= (long)pwm*PWM2_T/10000;        //PWM2在计数值为100H地方输出低电平                                       
                                                break;
                case 3:        PWM3T1= (long)pwm*PWM3_T/10000;        //PWM3在计数值为100H地方输出低电平                                       
                                                break;
                case 4:        PWM4T1= (long)pwm*PWM4_T/10000;        //PWM4在计数值为100H地方输出低电平
                                                break;
                case 5:        PWM5T1= (long)pwm*PWM5_T/10000;        //PWM5在计数值为100H地方输出低电平
                                                break;
                case 6:        PWM6T1= (long)pwm*PWM6_T/10000;        //PWM6在计数值为100H地方输出低电平
                                                break;
                case 7:        PWM7T1= (long)pwm*PWM7_T/10000;        //PWM7在计数值为100H地方输出低电平
                                                break;
        }
        P_SW2  &= ~0x80;  //以上寄存器为扩展sfr,访问后需将PSW2寄存器最高位置0
}
回复

使用道具 举报

ID:123289 发表于 2022-10-27 08:44 | 显示全部楼层
同频就更好处理了:
设计有N个通道要做PWM,用变量TB计时PWM的周期,各通道再用变量TB1,TB2......,TBN计时负脉冲的时间。
用定时器定个基本时钟,中断服务程序做下列两个动作:
1、对周期计时:TB-1。
PWM计满时各通道清0,TB重置,TB1,TB2......,TBN复位置数成各自的负脉冲的时间。
2、如果TBx<>0,就 -1,当TBx计满时(TBx=0时),x通道就置1,TBx不重置保持0。
如果TBx=0,就不处理了。
这样就成了。程序很简单。
回复

使用道具 举报

ID:57657 发表于 2022-10-27 09:35 | 显示全部楼层
具体要看PWM控制什么,用逻辑分析仪捕捉。
回复

使用道具 举报

ID:1005634 发表于 2022-10-27 09:50 | 显示全部楼层
npn 发表于 2022-10-27 09:35
具体要看PWM控制什么,用逻辑分析仪捕捉。

作业 并没有要求要控制什么,就是输出一个相位差是周期时间/pwm路数的这么几路pwm矩形波
回复

使用道具 举报

ID:491577 发表于 2022-10-27 10:30 | 显示全部楼层
你认真计算了吗,你设置的PWM0-7全部都是一样的。你连自己的算法都搞不清楚
回复

使用道具 举报

ID:1034262 发表于 2022-10-27 10:34 | 显示全部楼层
STC8A8K64S4A12 或 STC8A8K64D4做楼主要求的PWM太方便了。
8路增强型PWM都是15位长度,同频率,每路PWM都可以独立的设置输出高电平和低电平的时刻,所以可以设置任意相位。
回复

使用道具 举报

ID:213173 发表于 2022-10-27 21:03 | 显示全部楼层
yjx156 发表于 2022-10-27 09:50
emmm课程作业 并没有要求要控制什么,就是输出一个相位差是周期时间/pwm路数的这么几路pwm矩形波

无标题.jpg
就按这个套路可以增加N路同频不同相PWM。
  1. #include<reg51.h>

  2. typedef unsigned int u16;
  3. typedef unsigned char u8;

  4. u8 i;

  5. sbit out1=P2^0;
  6. sbit out2=P2^1;
  7. sbit out3=P2^2;
  8. sbit out4=P2^3;


  9. void main()
  10. {   
  11.         TMOD= 0x01;                //设置定时器模式
  12.         TL0 = 0x18;                //设置定时初始值
  13.         TH0 = 0xFC;                //设置定时初始值
  14.         TF0 = 0;                //清除TF0标志
  15.         TR0 = 1;                //定时器0开始计时
  16.         ET0=1;        //开T0中断
  17.         EA=1;        //开总中断
  18.         while(1);
  19. }

  20. //定时器T1的中断服务函数
  21. void T0_time()  interrupt 1
  22. {   
  23.         TL0 = 0x18;                //设置定时初始值
  24.         TH0 = 0xFC;                //设置定时初始值
  25.         switch(i)
  26.         {
  27.                 case 0: out1=~out1; break;
  28.                 case 1: out2=~out2; break;
  29.                 case 2: out3=~out3; break;
  30.                 case 3: out4=~out4; break;
  31.         }
  32.         i=++i%4;
  33. }
复制代码



回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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