如何用at89c51单片机8*8矩阵·显示英文字母how are you? 程序 5
展开全部
#include <avr/io.h>
#include <avr/interrupt.h>
#define uchar unsigned char
#define uint unsigned int
#define LED_ctrl PORTB //列开关
#define LED_code PORTD //行扫描代码
uchar code[8];
uchar str[]={0x00,0x90,0x90,0xF0,0x90,0x90,0x90,0x00, //H
0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, //o
0x00,0x00,0xA8,0xA8,0xA8,0x50,0x50,0x00, //w
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x00,0x60,0x90,0x90,0x90,0x68,0x00, //a
0x00,0x00,0xD8,0x60,0x40,0x40,0x40,0x00, //r
0x00,0x00,0x60,0x90,0xF0,0x80,0x60,0x00, //e
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x90,0x90,0x90,0x70,0x10,0x60,0x00, //y
0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, //o
0x00,0x00,0x90,0x90,0x90,0x90,0x68,0x00, //u
0x00,0x60,0x90,0x10,0x60,0x40,0x00,0x40, //?
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //
volatile uchar flag_10ms=0,flag_move=0;
uchar i=0;
//动态扫描,显示一屏
void LED_dis(uchar word[])
{
for(uchar l=0;l<8;l++)
{
LED_ctrl=0xff;
LED_code=~word[l];
LED_ctrl=~(0x01<<l);
}
LED_ctrl=0xff;
}
//单片机初始化
void MCU_init(void)
{
DDRB=0Xff;
DDRD=0Xff;
LED_ctrl=0xff;
LED_code=0xff;
}
//中断计时初始化
void timer0_init(void)
{
TCNT0=100;
TCCR0=0x02;
TIMSK|=(1<<TOIE0);
}
//中断服务程序,这里设置时有些随意,大概是1.25ms一个周期
ISR(TIMER0_OVF_vect)
{
static uchar k=0;
TCNT0=100;
flag_10ms=1; //每中断扫描一次,即LED屏点亮一次,如要加大LED亮度,可适当修改以增加点空比
if(++k>=100)
{
flag_move=1; //100中断约125毫秒间隔标志位,每次移动字幕一列,速度可由K调节
k=0; //这里本不该有注释,但是居然忘记了初始化,整整查错查了将近一个半小时,楞是没看出来忘记初始化,要命啊.
}
}
int main(void)
{
MCU_init();
timer0_init();
sei();
while(1)
{
if(flag_move==1)
{
uchar a,b;
flag_move=0;
if(i++==106)i=0;
a=i/8;
b=i%8;
for(uchar j=0;j<8;j++)
{
code[j]=(str[a*8+j]<<b)|(str[a*8+j+8]>>(8-b)); //这个程序最费工夫就是这个公式,移屏的算法,详细见程序后
}
}
else if(flag_10ms==1)
{
flag_10ms=0;
LED_dis(code);
}
}
}
//第一次玩LED点阵,花了很长时间总算搞定,起先用二维数组,用起来发现自己对二维数组和指针不熟,又整合成一维
//移屏公式请注意,因为我这个屏采用是的列开关,行扫描,移屏采用横移(左右平移),所以公式相对复杂一些,
//如果是上下纵移,或者是行开关列扫描的横移,应该相对会简单一些,只要在显示一屏的子函数中将位置错开一个即可
//本程序在GCC,mega16最小系统板上测试通过,51请自行改动中断接口以及输出端口即可,没用到AVR专有特性.
#include <avr/interrupt.h>
#define uchar unsigned char
#define uint unsigned int
#define LED_ctrl PORTB //列开关
#define LED_code PORTD //行扫描代码
uchar code[8];
uchar str[]={0x00,0x90,0x90,0xF0,0x90,0x90,0x90,0x00, //H
0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, //o
0x00,0x00,0xA8,0xA8,0xA8,0x50,0x50,0x00, //w
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x00,0x60,0x90,0x90,0x90,0x68,0x00, //a
0x00,0x00,0xD8,0x60,0x40,0x40,0x40,0x00, //r
0x00,0x00,0x60,0x90,0xF0,0x80,0x60,0x00, //e
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
0x00,0x90,0x90,0x90,0x70,0x10,0x60,0x00, //y
0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, //o
0x00,0x00,0x90,0x90,0x90,0x90,0x68,0x00, //u
0x00,0x60,0x90,0x10,0x60,0x40,0x00,0x40, //?
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //
volatile uchar flag_10ms=0,flag_move=0;
uchar i=0;
//动态扫描,显示一屏
void LED_dis(uchar word[])
{
for(uchar l=0;l<8;l++)
{
LED_ctrl=0xff;
LED_code=~word[l];
LED_ctrl=~(0x01<<l);
}
LED_ctrl=0xff;
}
//单片机初始化
void MCU_init(void)
{
DDRB=0Xff;
DDRD=0Xff;
LED_ctrl=0xff;
LED_code=0xff;
}
//中断计时初始化
void timer0_init(void)
{
TCNT0=100;
TCCR0=0x02;
TIMSK|=(1<<TOIE0);
}
//中断服务程序,这里设置时有些随意,大概是1.25ms一个周期
ISR(TIMER0_OVF_vect)
{
static uchar k=0;
TCNT0=100;
flag_10ms=1; //每中断扫描一次,即LED屏点亮一次,如要加大LED亮度,可适当修改以增加点空比
if(++k>=100)
{
flag_move=1; //100中断约125毫秒间隔标志位,每次移动字幕一列,速度可由K调节
k=0; //这里本不该有注释,但是居然忘记了初始化,整整查错查了将近一个半小时,楞是没看出来忘记初始化,要命啊.
}
}
int main(void)
{
MCU_init();
timer0_init();
sei();
while(1)
{
if(flag_move==1)
{
uchar a,b;
flag_move=0;
if(i++==106)i=0;
a=i/8;
b=i%8;
for(uchar j=0;j<8;j++)
{
code[j]=(str[a*8+j]<<b)|(str[a*8+j+8]>>(8-b)); //这个程序最费工夫就是这个公式,移屏的算法,详细见程序后
}
}
else if(flag_10ms==1)
{
flag_10ms=0;
LED_dis(code);
}
}
}
//第一次玩LED点阵,花了很长时间总算搞定,起先用二维数组,用起来发现自己对二维数组和指针不熟,又整合成一维
//移屏公式请注意,因为我这个屏采用是的列开关,行扫描,移屏采用横移(左右平移),所以公式相对复杂一些,
//如果是上下纵移,或者是行开关列扫描的横移,应该相对会简单一些,只要在显示一屏的子函数中将位置错开一个即可
//本程序在GCC,mega16最小系统板上测试通过,51请自行改动中断接口以及输出端口即可,没用到AVR专有特性.
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询