一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
楼主: benxiong22
收起左侧

avr单片机又遇到神奇的问题,求助

[复制链接]
 楼主| 发表于 2017-3-4 23:53 | 显示全部楼层
nengcai0313 发表于 2017-3-4 23:44
需要看完整程序,我考虑你的中断服务程序一直在进中断,初始化太早,因为你的中断服务程序的执行时间是比较 ...

我是用一个定时器实现3路pwm调光,实现3路调光
ISR(TIMER1_COMPB_vect)
{

unsigned int count;
for(count=1;count<num;count++) //num是pwm分辨率
{
  if(count<R_ZKB)
  {
   R_ON();             //当红色占空比大于计数值时点亮
  }
  else R_OFF();                 //否则就关闭红色
  if(count<G_ZKB)
  {
   G_ON();   
  }
  else G_OFF();
  if(count<B_ZKB)
  {
   B_ON();   
  }
  else B_OFF();  
}
FLAG=1;
}
 楼主| 发表于 2017-3-4 23:55 | 显示全部楼层
nengcai0313 发表于 2017-3-4 23:45
AVR可以直接输出脉宽调制信号的,不需要这样费事。

我想试试RGB调光,现在是用一个定时器实现3路pwm。
如果用oc输出引脚输出pwm信号,我的开发板的led没有接在这些脚上,没法实验
 楼主| 发表于 2017-3-5 00:03 | 显示全部楼层
nengcai0313 发表于 2017-3-4 23:44
需要看完整程序,我考虑你的中断服务程序一直在进中断,初始化太早,因为你的中断服务程序的执行时间是比较 ...

以下是完整程序,就是网上找的一个rgb调光程序改的。我一楼没有贴全部代码,是怕别人看见那么长就不帮我看了
/******************************************************************
函数功能:利用pwm技术控制RGB全彩灯变色和呼吸的实验
说    明:可以设置全彩灯在1600万色之间进行变化,也可以选择一些特定颜色
          进行呼吸,本程序为个人原创,转载请注明出处

者:空心菜

联系  QQ190719416

    期:2016/8/5

*******************************************************************/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define R_ON()  PORTB&=~((1<<PB0)|(1<<PB1))
#define R_OFF()  PORTB|=(1<<PB0)|(1<<PB1)
#define G_ON()  PORTB&=~((1<<PB2)|(1<<PB3))
#define G_OFF()  PORTB|=(1<<PB2)|(1<<PB3)
#define Y_ON()  PORTB&=~((1<<PB4)|(1<<PB5))
#define Y_OFF()  PORTB|=(1<<PB4)|(1<<PB5)
#define B_ON()  PORTB&=~((1<<PB6)|(1<<PB7))
#define B_OFF()  PORTB|=(1<<PB6)|(1<<PB7)
unsigned int R_ZKB=1,G_ZKB=1,B_ZKB=1;
unsigned int num=100;         //num的值最大可设置为255,当设置成255,且在变色模式下能达到1600万色
unsigned char FLAG;
void T1_Normal_Init()
{
OCR1A=120;   //12M晶振
TIMSK|=(1<<OCIE1B);//OCIE1A=1;
TCCR1A=0x00;
TCCR1B=0x08;   //ctc模式
TCCR1B|=0x01;  //分频设置
sei();
}
void main()
{  
DDRA=0xff;    //打开led总开关
PORTA=0xfb;

DDRB=0xff;    //PB设为输出
PORTB=0xff;   //上拉电阻

T1_Normal_Init();
while(1)
{

  if(FLAG)
{
   FLAG=0;
   R_ZKB+=1;
   if(R_ZKB>=num)
   {
    R_ZKB=1;
    G_ZKB+=1;
    if(G_ZKB>=num)
    {
     G_ZKB=1;
     B_ZKB+=1;
     if(B_ZKB>=num)
     {
      B_ZKB=1;
     }
    }
  }                            //以上为全彩变色模式
}  
}
}
/**************************************************************
函数功能:定时器0中断服务函数
说    明:设置定时溢出时间为10us,频率10khz,当进入中断后,为了避免
          在程序执行过程中未完又进入下一次中断,先关闭定时器,当此
     段程序执行完再打开定时器,并设置一个标志位,给主函数去判断
***************************************************************/
ISR(TIMER1_COMPB_vect)
{

unsigned int count;
for(count=1;count<num;count++) //分辨率为num
{
  if(count<R_ZKB)
  {
   R_ON();             //当红色占空比大于计数值时点亮
  }
  else R_OFF();                 //否则就关闭红色
  if(count<G_ZKB)
  {
   G_ON();   
  }
  else G_OFF();
  if(count<B_ZKB)
  {
   B_ON();   
  }
  else B_OFF();  
}
FLAG=1;
}

发表于 2017-3-5 00:10 | 显示全部楼层
如果你的定时器设置的跟他的一样的话,那么确实你的中断服务程序执行时间不够。原参数是计数120个周期,对应的是12M的时钟,AVR的速度是每时钟周期1条指令,你的终端服务程序在120个周期内执行不完,这还不包括进中断和出中断的8个周期时间(好像是8个,记不清了)
 楼主| 发表于 2017-3-5 00:42 | 显示全部楼层
nengcai0313 发表于 2017-3-5 00:10
如果你的定时器设置的跟他的一样的话,那么确实你的中断服务程序执行时间不够。原参数是计数120个周期,对 ...

avr中断我看别人说是进入中断服务程序后,会自动关闭中断响应,中断服务程序执行完毕后会自动开启中断响应,怎么还会存在执行时间不够的问题呢?
他用的是什么单片机我不知道,他的中断服务程序开始和结束是写有关中断和开中断代码的,因为avr会自动开关中断,所以我没写,确实也能重复响应中断。
我在占空比变量定义语句前面加了关键字volatile后,已经能调光了,但是闪烁的厉害,还需找找问题
 楼主| 发表于 2017-3-5 01:45 | 显示全部楼层
本帖最后由 benxiong22 于 2017-3-5 01:54 编辑

程序基本正常了,但是那段全彩1600万变色代码,觉得写得有问题,他的逻辑是这样的,RGB各255级亮度,255x255x255=1600万。
代码逻辑是:
R从1到255每循环一次,G加一级亮度;
G从1到255每循环一次,B加一级亮度;
因此,三重循环走完后,遍历了1600万种组合。
问题在于,R从1增加到255后,是突变为1的,因此看起来就是红色led一灭一亮的。因为我是用三个独立的红绿蓝led代替的,所以闪烁明显,也就是我前面说的闪烁的问题。如果用RGB三色led,估计亮度也会看起来闪烁吧
 楼主| 发表于 2017-3-6 13:49 来自手机 | 显示全部楼层
找了块3通道恒流的led驱动板接上rgb灯测试,果然,如果调快了一个劲的闪烁,调慢了等一整天也看不到循环完一遍所有颜色......
IMG_1161.JPG
IMG_1162.JPG
 楼主| 发表于 2017-3-6 19:46 来自手机 | 显示全部楼层
改成1~255,再255~1的来回扫,这样就不突兀的闪烁了
发表于 2017-3-6 21:04 | 显示全部楼层
如果是我,我会这么写:(虽然这也不是教科书中经典的PWM控制)

main()
{    LED_duty = 50 ;
    while(1)
   {   
        /*  
           在这里可以写一些逻辑判断语句,之后为LED_duty 赋值
           LED_duty = 150 ;
        */


        if(count<LED_duty)
            LED_ON();             //当计数值小于占空比时点亮
        else
            LED_OFF();           //否则就关闭
    }
}

ISR(TIMER1_COMPB_vect)
{
     count++;     
}

 楼主| 发表于 2017-3-7 20:56 来自手机 | 显示全部楼层
pla155 发表于 2017-3-6 21:04
如果是我,我会这么写:(虽然这也不是教科书中经典的PWM控制)

main()

你把点亮语句放在main里不行吧,main里语句稍微多一点肯定就闪烁的不行,放在中断里可以简单的调整定时器参数来调整pwm的频率

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-5-4 17:06 , Processed in 0.052396 second(s), 34 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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