原创 AVR程序

2007-3-5 15:56 4163 3 3 分类: MCU/ 嵌入式

本代码为我用AVR做的第一个实际应用程序,转载请注明作者及出处。


严禁用于商业用途,作者保留一切权利。


需要了解本代码应用的朋友,请QQ联系。QQ:93342183


作者:木瓜


完成时间:2007.01.27


#include <stdio.h>
#include <avr/io.h>   //必须包含此头文件
#include <avr/iom162.h>  //这个头文件可以不要,如果在makefile里面定义了的话
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <avr/wdt.h>


//#define F_CPU 14745600UL  //在MakeFile里定义过了,这里就不必再做定义macro了
//#define LenNum 1    //每次送的象素点数
uint8_t LenNum = 2;
uint8_t EveryColorSendNum = 2;  //
#define totallen 6000
#define sbi(PORTX,n) (PORTX |= (1<#define cbi(PORTX,n) (PORTX &= ~(1<#define NOP() __asm__ __volatile__ ("nop")


uint8_t MoveNum="0";      //跑动色计数,用作判断跑动色当前在哪个象素显示
uint8_t LedNum0=0;      //背景色计数,本程序用不到,因为这里的背景色是整体的,不是断开的
uint8_t ChangFlag="1";     //是否发送数据标志,发送完一组数据就置1,然后清0,再发送色彩显示数据
uint8_t BackColor="0";    //当前背景色,这个东西好理解
uint8_t MoveColor="0";   //当前跑动色,这个东西好理解
uint8_t SendNum = 0;
uint8_t MoveColor7 = 0;
uint8_t Timer0Flag=0;
uint8_t RecData;
uint8_t MoveColorCopy;
uint8_t LedSO0,LedSO1;  //闪烁指示灯控制
uint8_t data[3];
uint8_t RecBuffer[6];
uint8_t RecADDL="0";


void Init_Uart(void)

 UCSR0B=0x00;   //RX Complete Interrupt disable and Receive disable
 UCSR0A &=0xFD;  //异步模式。
 UCSR0C=0x86;   //写UCSRC.bit7.URSEL=1,异步模式bit6.UMSEL=0,无奇偶校验UPM1:0=00,一位停止位USBS=0,8位数据UCSZ2:0=011,时钟极性UCPOL=0,上升沿改变数据
 UBRR0H=0x00;
 UBRR0L=95;        //9600 ,UBRR=Fosc/(16*BAUD)-1=96-1=95
 UCSR0B=(1<}



ISR(USART0_RXC_vect)

 uint8_t i,temp;
 cli();
 temp=UDR0;
 RecBuffer[RecADDL++]=temp;
 
 if(RecBuffer[RecADDL-1]==0x0D)
  {
   RecADDL=0;
   if(RecBuffer[0]==0xFF)
   {
    if(RecBuffer[1]==0xFF)    
    { 
     LenNum=3;
    }
    else if(RecBuffer[1]==0xFE)
    { 
     LenNum=1;
    }
    
    if(RecBuffer[2]==0xFF)
     EveryColorSendNum=1;
    else if(RecBuffer[2]==0xFE)
     EveryColorSendNum=4;
      
    if(RecBuffer[3]==0xFF)
     cbi(PORTB,2);
    else if(RecBuffer[3]==0xFE)
     sbi(PORTB,2);
     
    if(RecBuffer[4]==0xFe)    //复位信号
    {
     wdt_disable();
     wdt_enable(WDTO_15MS);
     while(1);
    }     
   }
   else
    sbi(PORTB,2);
  } 
 sei();
}
void Init_ports(void)
{
 DDRB =0xFF;   //定义端口方向
 DDRD =0xFF;
 DDRE =0xFF;
}


void Init_timer0(void)
{
/* TCNT0 = 0x71;  //初始化定时器0数据寄存器,和下面的分频设定决定其定时为100HZ
 TCCR0 = 5;   //预分频为clk/1024,如果TCCR0的值为1-5,则为定时方式,6-7则为计数方式
      //事实上,计数器与定时器的本质是一样的,区别仅在于一个是对外部信号进行计数,
      //一个是对内部时钟进行计数,读者只要理解了定时器,就能很轻松地使用计数器了
 TIMSK|=(1<      //TOIE0即Timer0的溢出中断使能位
      //如果用到外中断,必须设定GICR使能外部中断,设定MCUCR确定外中断触发方式
*/   
}
void Init_timer1(void)
{
 TCNT1L = 0x71;  //初始化定时器0数据寄存器,和下面的分频设定决定其定时为100HZ
 TCNT1H = 0xFF;
 TCCR1A = 0;
 TCCR1B = 5;   //预分频为clk/1024,如果TCCR0的值为1-5,则为定时方式,6-7则为计数方式
      //事实上,计数器与定时器的本质是一样的,区别仅在于一个是对外部信号进行计数,
      //一个是对内部时钟进行计数,读者只要理解了定时器,就能很轻松地使用计数器了
 TIMSK|=(1<      //TOIE0即Timer0的溢出中断使能位
      //如果用到外中断,必须设定GICR使能外部中断,设定MCUCR确定外中断触发方式 
}
void Init_devices(void)
{
 cli();   
 wdt_disable();
 LedSO0=20;
 LedSO1=0;
 MCUCR=0xC3;  
 Init_ports();
 Init_timer1();   
 Init_Uart();
 wdt_enable(WDTO_2S);
 sei();    //全局中断开
}


void fillcolor(void)
{
 uint16_t i,j;
 
 data[0]=1;
 data[1]=0;
 data[2]=1;


// cbi(PORTB,2);    //595使能,这个信号经调试是对的
 cbi(PORTB,1);    //锁存STB,锁存应该放在数据操作之前
 for(i=0;i {
  for(j=0;j<3;j++)  //送出RGB三位数据
  {
   if(data[j]==0)  //根据data[]的值,决定data引脚的数据
   {
    cbi(PORTB,0);
   }
   else
   { 
    sbi(PORTB,0);
   }  
   sbi(PORTB,3);  //移位时钟
   cbi(PORTB,3);  
  }
 }
 sbi(PORTB,1);    //打开锁存,输出数据
 cbi(PORTB,1);    //锁存STB,锁存应该放在数据操作之前
}


void SendData(void)
{
 uint8_t i,j;    //j为数组元素序号,不能定义为有符号型变量
 
// cbi(PORTB,2);    //595使能,这个信号经调试是对的
 cbi(PORTB,1);    //锁存STB,锁存应该放在数据操作之前
 for(i=0;i {
  switch(MoveColor)    //当前跑动色,7种显示搭配
  {
   case 0:
    data[0]=0;
    data[1]=0;
    data[2]=0;
    break;
   case 1:
    data[0]=0;
    data[1]=0;
    data[2]=1;
    break;
   case 2:
    data[0]=0;
    data[1]=1;
    data[2]=0;
    break;
   case 3:
    data[0]=0;
    data[1]=1;
    data[2]=1;
    break;
   case 4:
    data[0]=1;
    data[1]=0;
    data[2]=0;
    break;
   case 5:
    data[0]=1;
    data[1]=0;
    data[2]=1;
    break;
   case 6:
    data[0]=1;
    data[1]=1;
    data[2]=0;
    break;
   case 7:
    data[0]=1;
    data[1]=1;
    data[2]=1;
    break;
   default:
    data[0]=1;
    data[1]=1;
    data[2]=0;
    break;
  }
  for(j=0;j<3;j++)   //送出RGB三位数据
  {
   if(data[j]==0)   
   {
    cbi(PORTB,0);
   }
   else
   {
    sbi(PORTB,0);
   }
     
   sbi(PORTB,3);   //移位时钟
   cbi(PORTB,3);
  }  
 }
 sbi(PORTB,1);     //打开锁存,输出数据
 cbi(PORTB,1);     //锁存STB,锁存应该放在数据操作之前
}


ISR(TIMER1_OVF_vect)    //新版GCC的中断服务函数入口,接近Linux

 cli();       //关全局中断,如果希望中断期间能响应其他中断,就用sei();
// TCNT0 = 0X71;     //重新载入定时初值
 
 TCNT1L = 0x71;  //重新载入定时初值
 TCNT1H = 0xFF;
 if(Timer0Flag<5)
 {
  Timer0Flag++;
 }
 else
 {
  Timer0Flag=0;
  SendData(); 
  if(SendNum==EveryColorSendNum)
  { 
   SendNum=0;
   if(MoveColor<7)
   {
    MoveColorCopy=MoveColor;
    MoveColor=7;
   }   
   else
   {
    MoveColor=MoveColorCopy;
    MoveColor++;
    if(MoveColor==7)
    { 
     MoveColor=0;
    }
   } 
  }  
  else if(SendNum  {
   SendNum++;
  }  
 } 
 if(LedSO0!=0)
 {
  LedSO0--;
  if(LedSO0==0)
  {
   LedSO1=20;
   sbi(PORTD,3);
  }
 }
  
 if(LedSO1!=0)
 {
  LedSO1--;
  if(LedSO1==0)
  {
   LedSO0=20;
   cbi(PORTD,3);
  }
 }
 sei();
}


int main(void)
{
 Init_devices();
 cbi(PORTB,2);    //595使能,这个信号经调试是对的
 cbi(PORTB,1);    //锁存STB,锁存应该放在数据操作之前
 fillcolor();
 while(1)
 { 
//  uint8_t i; 
  wdt_reset();//AVR单片机喂狗指令,和wdt_disable();wdt_enable(WDTO_2S);两条指令一起用,
        //wdt_disable()为关闭看门狗
        //wdt_enable(WDTO_2S)为初始化并打开看门狗,使用该指令后
        //必须在规定的时间内运行wdt_reset()指令喂狗,否则复位
  printf("Ready for FLASH programming.\n");
  
 }
 return(0);
}


 

文章评论0条评论)

登录后参与讨论
我要评论
0
3
关闭 站长推荐上一条 /2 下一条