本帖最后由 symmetry 于 2012-8-1 23:21 编辑
原帖地址http://www.027mcu.cn/174.html
配套演示视频http://v.youku.com/v_show/id_XNDE3ODI1MDI4.html?f=17768588
1.1.1 项目需求
点亮发光二极管,反复来回摇晃时显示出LOVE字符
1.1.2 背景资料:(遥遥棒原理)
利用人眼的视觉暂留现象,用1列LED灯快速向左或向右摇动,视觉效果呈现出LED阵列的效果。
关键是在1列LED向右或向左摇动的时候,这一列LED灯在1-8的各个位置点亮相应的LED灯,使得8列整体组成一个图案。
1.1.1 方案设计
因此程序可以设置1列LED灯按一定的时间间隔依次显示1-8位置上所需的图案,时间间隔的设置取决于从1位置摇动到2位置所需要的时间,通常为几毫秒。1-8位置上的图案显示顺序可以是从左到右,也可以是从右到左,如选取从左到右的顺序显示(1-8),则在LED灯从右到左摇回来时如还按(1-8)显示,整体组成的图案就会不对,因此从右到左摇时或者LED不显示,或者按照(8-1)的顺序显示,为程序简便起见,设置从右到左摇动时LED不显示。
1.1.2 详细设计
1.1.2.1 硬件设计(行程开关)
为控制LED在从左向右摇时显示,从右向左摇时不显示。硬件上必须有一个开关来通知单片机摇摇棒什么时候是在从左向右摇 什么时候是在从右向左摇。因此我们需要一个行程开关。可以用水银开关,或者自己做一个类似钟摆的小开关,当摇摇棒从左向右摇时,开关始终处于闭合状态,如图 当摇摇棒从右向左摇时,开关始终处于断开状态 如图 ,这个小开关与单片机的外部中断0即INT0连接,就可以利用中断程序来完成摇摇棒的功能。当摇摇棒从左向右摇时,小开关闭合,INT0变为低电平,触发中断,中断服务程序中,让LED按次序显示图案,当摇摇棒从右向左摇时,小开关处于断开状态,中断不会被触发。LED也不会显示图案。需要注意中断服务程序必须要在从左到右摇的1s左右的时间内执行完,否则当摇摇棒从右到左摇回时,中断服务程序仍在执行,即LED仍在显示图案,会造成混乱。
1.1.1.1 软件设计(字模软件)
P0口和P2口共16个IO口控制16盏LED灯为一列,这列LED灯亮灭来显示出图案。
要显示出的效果,P0=0x?? P2=0x??
这样P0 = 0×08 P2 = 0×20 即显示出的效果,要显示出的效果需要后7列的字模码,靠自己一列一列算有些麻烦,有软件可以自动生成
提取字模
图中每一个小方块就代表一个LED灯,因硬件16盏LED灯为一列,这里对应选取字高为16个小方块,字宽可以自行选取,这里选16
字宽32X字高16大写字母“L”生成的字模码为0×08,0×20,0xF8,0x3F,0×08,0×20,0×00,0×20,0×00,0×20,0×00,0×20,0×00,0×30,0×00,0×00
只需要P0依次 = 0×08,0xF8,0×08,0×00…0×00(第1,3,5,7,9,11,13,15字模码)
P2依次 = 0×20,0x3F,0×20,0×20…0×00(第2,4,6,8,10,12,14,16个字模码) 即可有如图显示效果
下面按这个思路进行程序编写
软件设计
程序代码:
/*******************************************************************************
** 文 件 名: shakeL.c
** Copyright (c) 2011 汉核科技 hancore tech
** 创 建 人: Monkey.Wuhan.Sun
** 描 述: LED摇摇棒显示64*16像素 外部中断方式INT0显示;取模方式:纵向取模、字节倒序
** 日 期: 2011.04
** 修 改:
** 日 期:
** 版 本: R1A
*******************************************************************************/
#include <reg52.h>
#define uchar unsigned char //宏定义
#define uint unsigned int //宏定义
#define KEY P3^2 //定义画面切换按键
uchar pic=0; //pic为按键次数;初始化
uchar code love[] = {
0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,
0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0xFE,0x3F,0×00,0×20,0×00,0×20,0×00,0×20,
0×00,0×20,0×00,0×20,0×00,0×20,0×00,0×20,0×00,0×00,0×00,0×00,0×00,0×00,0xF8,0x0F,
0×04,0×10,0×02,0×20,0×02,0×20,0×02,0×20,0×02,0×20,0×04,0×10,0xF8,0x0F,0×00,0×00,
0×00,0×00,0×00,0×00,0xFE,0×07,0×00,0×08,0×00,0×10,0×00,0×20,0×00,0×20,0×00,0×10,
0×00,0×08,0xFE,0×07,0×00,0×00,0×00,0×00,0×00,0×00,0xFE,0x3F,0×82,0×20,0×82,0×20,
0×82,0×20,0×82,0×20,0×82,0×20,0×82,0×20,0×82,0×20,0×00,0×00,0×00,0×00,0×00,0×00,
0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00,/*LOVE*/
}; //输出LOVE 4个字母 每个字母16高X16宽 4个字母 一共16X64 字模输出方式: 16X16 阴码 逐列式
uchar code heart[] = {
0xF8,0×00,0xFC,0×01,0xFE,0×03,0xFF,0×07,0xFF,0x0F,0xFE,0x1F,0xFC,0x3F,0xF8,0x7F,
0xF8,0x7F,0xFC,0x3F,0xFE,0x1F,0xFF,0x0F,0xFF,0×07,0xFE,0×03,0xFE,0×01,0xF8,0×00,/*”心形图案16X16″,0*/
0xF8,0×00,0xFC,0×01,0xFE,0×03,0xFF,0×07,0xFF,0x0F,0xFE,0x1F,0xFC,0x3F,0xF8,0x7F,
0xF8,0x7F,0xFC,0x3F,0xFE,0x1F,0xFF,0x0F,0xFF,0×07,0xFE,0×03,0xFE,0×01,0xF8,0×00,/*”心形图案16X16″,0*/
0xF8,0×00,0xFC,0×01,0xFE,0×03,0xFF,0×07,0xFF,0x0F,0xFE,0x1F,0xFC,0x3F,0xF8,0x7F,
0xF8,0x7F,0xFC,0x3F,0xFE,0x1F,0xFF,0x0F,0xFF,0×07,0xFE,0×03,0xFE,0×01,0xF8,0×00,/*”心形图案16X16″,0*/
0xF8,0×00,0xFC,0×01,0xFE,0×03,0xFF,0×07,0xFF,0x0F,0xFE,0x1F,0xFC,0x3F,0xF8,0x7F,
0xF8,0x7F,0xFC,0x3F,0xFE,0x1F,0xFF,0x0F,0xFF,0×07,0xFE,0×03,0xFE,0×01,0xF8,0×00,/*”心形图案16X16″,0*/
}
/*****函数声明*****/
void display1(void);
void display2(void);
/*****n(us)延时子程序*****/
void DelayUs(uint N)
{
uint x;
for(x=0; x<=N;x++);
}
/*****中断服务程序*****/
void intersvr0(void) interrupt 0 using 1 //using 1 即使用1号寄存器组 如不写 则编译软件自动分配寄存器组给该中断
{
switch(pic) //选择画面
{
case 0:{display1();}break; //pic = 0 调用display1()
case 1:{display2();}break; //pic = 1 调用display2()
default:display1(); //默认 调用display1()
}
}
/*****显示子程序1(LOVE)*****/
void display1(void) //输出LOVE 4个字母 每个字母16高X16宽 4个字母 一共16X64 字模输出方式: 16X16 阴码 逐列式
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++) //128个8位编码,64个上8盏led 64个下8盏led,因此是64一个循环
{
P0=~love[i*2]; //上8盏灯按照双数编码亮灯 字模输出方式 16X16 阴码 逐列式 4个字母一共16X64 1个字母16位宽16位高,就有16X2=32个8位编码,4个字母就是16X2X4=128个8位编码,
P2=~love[i*2+1]; //下8盏等按照单数编码亮灯
DelayUs(120);
}
}
/*****显示子程序2(心形图案)*****/
void display2(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++)
{
P0=~heart[i*2];
P2=~heart[i*2+1];
DelayUs(120);
}
}
/*****主函数*****/
void main(void)
{
IT0=0; //0为低电平中断,1为下降沿中断
EX0=1; //使能外部中断0
EA=1; //总中断使能
while(1) //主程序中只检测按键
{
if(KEY==0) //画面切换键按下
{
DelayUs(10000); //按键去抖
if(KEY==0);
pic++;}
if(pic>1)pic=0; //按按键使 pic在01之间变换 pic = 0 显示“LOVE” pic = 1显示心形图案
}
}
/*****END*****/ |
|