本代码为我用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条评论)
登录后参与讨论