找回密码
 立即注册
查看: 2106|回复: 12

使用STC8H单脉冲模拟300-900ns协议遇到的...

[复制链接]
  • TA的每日心情

    2024-5-3 14:22
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    3

    主题

    20

    回帖

    149

    积分

    注册会员

    积分
    149
    发表于 2022-12-15 09:35:49 | 显示全部楼层 |阅读模式
    本帖最后由 flyarm 于 2022-12-15 15:26 编辑

    项目需求:使用PWM功能实现,300-900ns的协议控制

    硬件实现: MCU--stc8h1k08      

    需求分析:
    300.png
    根据时序要求 需要产生300ns 和 900ns的高脉冲;此类信号(红外遥控协议,WS2812等)一般精确模拟高脉冲即可,低脉冲要求不高;以24M时钟计算,1us就是需要24个脉冲,300ns需要(24*3/10)约7-8个脉冲;900ns需要(24*9/10)约21-22个脉冲;   程序中使用40个脉冲周期;
    如果有PWM+DMA效果应该会更好,因为我用的芯片不支持DMA所以只能放弃;

    代码,使用pwm的2P作为输出:


    void PWMA_OUT_Configuration(void)
    {
      //使用PWM2P输出
        P_SW2 |= 0x80;                              //使能XFR访问
      //  PWMA_Priority(0);

        PWMA_CCER1 = 0x00;   
        PWMA_CCMR2 = 0x60;                          //设置2p PWM2 模式2 输出,启用预装载

        PWMA_CCER1  = 0x30;                         //使能2P通道,比较输出高 有效;
            
        PWMA_SR1 = 0;                               //清标志位
        PWMA_CNTR = 0;                              //清计数器
      
        PWMA_ENO = 0x00;
        PWMA_ENO = ENO2P;                     //使能输出                ENO4P|ENO3N||ENO1N

        PWMA_PS = 0x00;                       //高级 PWM 通道输出脚选择位
        PWMA_PS = PWM2_SW_P12_P13;   
      
        PWMA_ARR = 40;
        PWMA_CCR2 = 30;            

        PWMA_BRK = 0x80;                            //使能主输出
        PWMA_CR1 = 0x88;                           //开始计时  单次脉冲
    }


    void OutPWM_byte(unsigned char Dout)        //先发高位,把每一位转化成一个pwm脉冲输出
    {
            unsigned char i;
            bit        Dbit=0;        

            for(i=0;i<8;i++)
            {
                    Dbit        =        (Dout>>(7-i))&0x01;                //从高到低获取bit
                    if(Dbit)        {PWMA_CCR2 = 18;}       //40-22
                    else                        {PWMA_CCR2 = 33;}        //40-7
                    PWMA_CR1 |= 0x01;
                    NOP1();                                //每个脉冲的总周期逐渐变小,why?
            }
            NOP40();
    }



    主程序测试调用:
    ***********前面省略

            PWMA_OUT_Configuration();
            EA = 1;

            while (1)
            {
                    OutPWM_byte(0xF7);
                    delay_ms(5);
            }


    经测试,发现从第MSbit到LSBit,间隔周期逐渐变小,百思不得其解,不知道什么原因;等会补充一个测试图:
    tt.png



    回复 送花

    使用道具 举报

    该用户从未签到

    46

    主题

    3053

    回帖

    6883

    积分

    超级版主

    积分
    6883
    发表于 2022-12-15 10:55:37 | 显示全部楼层
    WS2812S的标准时序如下:
    TH+TL = 1.25us±150ns, RES>50us
    T0H = 0.25us±150ns = 0.10us - 0.40us
    T0L = 1.00us±150ns = 0.85us - 1.15us
    T1H = 1.00us±150ns = 0.85us - 1.15us
    T1L = 0.25us±150ns = 0.10us - 0.40us
    两个位数据之间的间隔要小于RES的50us.

    使用PWM输出控制WS2812并不是好办法,但单脉冲输出不会有问题,先设置好单脉冲的参数,然后启动即可输出一个单脉冲。

    控制WS2812最简单的是用IO操作,但会占用MCU时间,一个灯耗时30us,灯数不多的话,时间占比可以接受就可以了。比如擦欧洲哦100个灯要3ms,20ms刷新一次,时间占比15%,仍有85%的时间给别的任务。
    建议使用SPI操作,有DMA更好。

    该用户从未签到

    551

    主题

    9550

    回帖

    1万

    积分

    管理员

    积分
    14011
    发表于 2022-12-15 11:01:15 | 显示全部楼层
    飞翔:已请到梁工关注您这个贴,你带老兄弟们在这讨论,将程序放上来,好分析
  • TA的每日心情

    2024-5-3 14:22
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    3

    主题

    20

    回帖

    149

    积分

    注册会员

    积分
    149
     楼主| 发表于 2022-12-15 11:10:38 | 显示全部楼层
    理论上肯定是优选spi+dma
    因为要在现有的pwm脚上实现 模拟协议;这样硬件上可以通用; 所以现在的方式就成了我的最优选择;

    单个脉冲实现没问题;现在就是连续输出的情况下,总觉得和寄存器配置配合不起来;可能是因为执行时间问题,我继续摸索
  • TA的每日心情

    2024-5-3 14:22
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    3

    主题

    20

    回帖

    149

    积分

    注册会员

    积分
    149
     楼主| 发表于 2022-12-15 11:44:20 | 显示全部楼层
    本帖最后由 flyarm 于 2022-12-15 12:03 编辑

    问题已解决,因为原发送代码 移位操作造成时间延时不同,所以周期有差异;
    改成如下即可:

    static void OutPWM_byte(unsigned char Dout)        //先发高位,把每一位转化成一个pwm脉冲输出
    {
            unsigned char i;
            unsigned char        Dbit=0;        

            for(i=0;i<8;i++)
            {
                    Dbit        =        Dout&0x80;                //从高到低获取bit
                    if(Dbit)        {PWMA_CCR2 = 18;}
                    else                        {PWMA_CCR2 = 33;}        
                    PWMA_CR1 |= 0x01;
                    Dout        =        Dout<<1;                                //等待的时间里 每次移位一次
                    while(PWMA_CR1 &0x01);
            }
    }


    稍晚改到2812灯,测试后上工程源码

    该用户从未签到

    551

    主题

    9550

    回帖

    1万

    积分

    管理员

    积分
    14011
    发表于 2022-12-15 12:00:42 | 显示全部楼层
    感谢分享,都是爱的奉献
  • TA的每日心情

    2024-5-3 14:22
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    3

    主题

    20

    回帖

    149

    积分

    注册会员

    积分
    149
     楼主| 发表于 2022-12-16 09:28:37 | 显示全部楼层
    基于PWM单脉冲的ws2812实现源程序

    PWM_WS2812.zip

    131.38 KB, 下载次数: 91

    该用户从未签到

    46

    主题

    3053

    回帖

    6883

    积分

    超级版主

    积分
    6883
    发表于 2022-12-16 11:06:28 | 显示全部楼层
    用PWM输出,并且用while等待,不如直接用IO输出,反正都是在那里里等待。
    //@24MHz
    sbit        DIN = P0^0;    //任意IO, 注意要在程序开始初始化IO为推挽输出
    void        Send_1us(void)
    {
            NOP(16);        // 6+16T  @24MHz,  实际14~40MHz均可驱动
    }

    void        Send_color(u8 color)        //发送一个字节颜色值
    {
            u8        i;
            i = 8;
            do
            {
                    EA = 0;        //发送时禁止中断
                    if((color & 0x80) != 0)   //数据1
                    {
                            DIN = 1;
                            Send_1us();
                            DIN = 0;   //1T
                            EA = 1;        //1T 发送完一个位数据后允许中断, 但任何中断处理时间要小于RES的50us.
                            NOP(4);        //4T @24MHz
                    }
                    else
                    {
                            DIN = 1;
                            NOP(5);                        // 6T @24MHz, 14~44MHz均可驱动
                            DIN = 0;
                            EA = 1;        //发送完一个位数据后允许中断, 但任何中断处理时间要小于RES的50us.
                            Send_1us();
                    }
                    color <<= 1;
            }
            while(--i != 0);
    }

    void        Send_GRB(u8 g, u8 r, u8 b)
    {
            Send_color(g);
            Send_color(r);
            Send_color(b);
    }
  • TA的每日心情

    2024-5-3 14:22
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    3

    主题

    20

    回帖

    149

    积分

    注册会员

    积分
    149
     楼主| 发表于 2022-12-16 14:08:16 | 显示全部楼层
    本帖最后由 flyarm 于 2022-12-16 14:14 编辑

    有道理  单任务用io更好;可是我的应用还有各种任务 中断要考虑,还是用pwm 方便

    有支持dma的PWM就更方便了,根本就不需要单脉冲;直接 DMA控制占空比发PWM就好了

    该用户从未签到

    0

    主题

    5

    回帖

    22

    积分

    新手上路

    积分
    22
    发表于 2023-4-17 13:16:11 | 显示全部楼层
    flyarm 发表于 2022-12-15 11:44
    问题已解决,因为原发送代码 移位操作造成时间延时不同,所以周期有差异;
    改成如下即可:

    while(PWMA_CR1&0X01)?为什么这样写?这样,意思是一个周期输出后,这个寄存器的值会自动的改变吗?我看手册 里面PWMA_CR1=0X01,这样是打开计数器,按照你这样写,难道计数器值等于预设值:PWMA_CCR2之后,这个计数器会自动关闭吗?
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-21 04:58 , Processed in 0.069680 second(s), 67 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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