第四课 多排 LED与LED点阵实验准备:使用前一课已装配好的实验板LED 增加8只 电阻 10k,增加8只 LED点阵 8x8 (或直接使用完整的开发板) 课程内容:一、 同时控制两排LED(16只LED)要继续增加控制LED数量,在P1的8个IO口用完的情况下,选择P2接另外8只LED,然后程序稍做修改,直接加入对P2的控制即可。 一般情况下,在启动KEIL软件之前,从之前的工程中复制一份出来修改使用,这有两个好处,一是保留前面的实验成果,二是无需再花时间输入相同的内容,复制后只须修改小小即可,省时省力。复制与粘贴这两个操作一定要熟练掌握。 例如,把之前的工程myled1 整个文件夹复制一份为myled2,只需在KEIL中打开这文件夹中的工程即可省去建新工程与设置的步骤。 以第三课其中一段程序修改来实验。(仅主程序main(0中增加 P2=~P2;) #include 'reg52.h' #define uint unsigned int #define uchar unsigned char sbit P10= P1^0; void mDelay(uint Delay) { uint i; for(;Delay>0;Delay--) for(i=0;i<> } void main() { P1=~P1; P2=~P2; mDelay(1000); } 同样,可参照第三课内容对第2排LED做花样控制,此处可自由实验下。 二、 LED点阵89C52单片机只有P0、P1、 P2、P3、P4四个IO组,如果超过32只LED,那么就不好控制了,例如这里的8x8点阵,里面有64只LED。 分析这LED点阵结构,可以见到,每只LED分别由横向一线与纵向一条控制,当LED对应横线设置信号 1(即5V电压),同时这只LED纵向的线设置信号0(即0V电压),这只LED就会发光。于是只需两组IO即可控制LED点阵。 先做个小实验,把LED点阵两排脚分别接P1与,修改前面的程序main()部分内容,如下: void main() { P1=0xFF; //控制横向线电压,提供5V电压 P2=0xAA; //控制纵向线电压,产生显示效果 mDelay(1000); } 编译,下载,可以见到LED点阵以行间隔方式点亮了(如果没有点亮,把P1、P2对调一下)。 再做下小改,如下: void main() { P1=0xFF; //控制横向线电压,提供5V电压 P2=0xDB; //控制纵向线电压,产生显示效果 mDelay(1000); } 编译,下载,可以见到LED点阵中间的某些点被控制点亮。 那么,如果想显示自己想要显示的指定的内容呢,例如显示数字,中文等,这就要逐行逐点来计算哪点位置给个0,哪点位置给个1,计算量特大了。 不过,单片机开发的前辈早就编起了一段代码,我们直接复制过来即可使用,当然想深层次学习,可以仔细研究。这里是易学教程,我们不用深究。 其实,生产或销售单片机零件模块的商家一般都会附送模块的资料和单片例程,这方便极了,我们只需要学会调用即可。例程如下: #include 'reg52.h' #define uchar unsigned char #define uint unsigned int //以下两大段数据称为数组 //数组row中有8个数,控制LED点阵高电平管脚 ,控制LED横向线电压 uchar code row[] ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //二维扫描数组,不同的显示内容,只需取出对应的一组数,控制LED纵向线 uchar code word[][8]={ {0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00}, //0 {0x00,0x00,0x00,0x00,0x21,0x7f,0x01,0x00}, //1 {0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00}, //2 {0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00}, //3 {0x00,0x00,0x0c,0x14,0x24,0x7f,0x04,0x00}, //4 {0x00,0x00,0x72,0x51,0x51,0x51,0x4e,0x00}, //5 {0x00,0x00,0x3e,0x49,0x49,0x49,0x26,0x00}, //6 {0x00,0x00,0x40,0x40,0x40,0x4f,0x70,0x00}, //7 {0x00,0x00,0x36,0x49,0x49,0x49,0x36,0x00}, //8 {0x00,0x00,0x32,0x49,0x49,0x49,0x3e,0x00}, //9 {0x00,0x00,0x7F,0x48,0x48,0x30,0x00,0x00}, //P {0x00,0x00,0x7F,0x48,0x4C,0x73,0x00,0x00}, //R {0x00,0x00,0x7F,0x49,0x49,0x49,0x00,0x00}, //E {0x00,0x00,0x3E,0x41,0x41,0x62,0x00,0x00}, //C {0x00,0x00,0x7F,0x08,0x08,0x7F,0x00,0x00}, //H {0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00}, //I {0x00,0x7F,0x10,0x08,0x04,0x7F,0x00,0x00}, //N {0x7C,0x48,0x48,0xFF,0x48,0x48,0x7C,0x00} //中 }; void mDelay(uint Delay) { uint i; for(;Delay>0;Delay--) for(i=0;i<> } void display(uchar word_num) { //参数 word_num 就是要显示的排在数组第几位置的显示内容 uchar i; for(i=0;i<> { P2 = row[i]; //取出对应的行扫描控制信号 P0=word[word_num][i]; //取出对应的列扫描控制信号,显示内容 mDelay(1); //延时1毫秒(1秒=1000毫秒) P2=0xff; P0=0xff; } } void main() { display(3); // 如此简单调用即可 } 从主程序 main()中可以看到,使用方法实在太简单了,就一个display()函数,只需换下括号中的显示参数即可。 现在可以实践下了,可以试下找LED点阵厂家配套的例程,或者上网搜索同类例程,或者直接就复制这一课教程中的代码,复制到自己的程序中,只要自己明白自己所调的模块实现什么效果,那么这个程序就变成你自己的程序了。 对于其他的模块也是类似,例如以后学习的模块:4段数码管,8路独立键盘,4x4矩阵键盘,Lcd1602,12864液晶屏,蜂鸣器模块,5轴步进电机模块,超声波模块,哨声模块,光线控制模块,DS18B02温度模块,VS838红外接收模块与7x3红外摇控器,继电器控制模块,带电池的DS1302实时时钟模块,支持SPI的各种模块,如液晶屏模块,SD卡模块,摄像头模块,MP3模块,FM收音机模块, … … 所以,学习C51单片机应用并不难,关键就是学会『拿』过来用,即是复制与粘贴相关代码。 三、 程序优化从前面的程序中看到,程序一大段代码,其中实现的功能可以让人重复使用。另外,从一些模块厂家提供的例程中,有些例程的部分代码是放入一个.h 的文件中。而让主程序部分简洁明了。 这个 . h文件称为 『头文件』,我们把可把常用的功能搬到头文件件,这头文件也可以复制给其他程序中,让其他程序受益。 示例,建立头文件 function.h 并化优程序。 头文件function.h内容:(注意保存时,要输入完整文件名function.h) #include 'reg52.h' #define uchar unsigned char #define uint unsigned int //以下两大段数据称为数组 //数组row中有8个数,控制LED点阵高电平管脚 ,控制LED横向线电压 uchar code row[] ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //二维扫描数组,不同的显示内容,只需取出对应的一组数,控制LED纵向线 uchar code word[][8]={ {0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00}, //0 {0x00,0x00,0x00,0x00,0x21,0x7f,0x01,0x00}, //1 {0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00}, //2 {0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00}, //3 {0x00,0x00,0x0c,0x14,0x24,0x7f,0x04,0x00}, //4 {0x00,0x00,0x72,0x51,0x51,0x51,0x4e,0x00}, //5 {0x00,0x00,0x3e,0x49,0x49,0x49,0x26,0x00}, //6 {0x00,0x00,0x40,0x40,0x40,0x4f,0x70,0x00}, //7 {0x00,0x00,0x36,0x49,0x49,0x49,0x36,0x00}, //8 {0x00,0x00,0x32,0x49,0x49,0x49,0x3e,0x00}, //9 {0x00,0x00,0x7F,0x48,0x48,0x30,0x00,0x00}, //P {0x00,0x00,0x7F,0x48,0x4C,0x73,0x00,0x00}, //R {0x00,0x00,0x7F,0x49,0x49,0x49,0x00,0x00}, //E {0x00,0x00,0x3E,0x41,0x41,0x62,0x00,0x00}, //C {0x00,0x00,0x7F,0x08,0x08,0x7F,0x00,0x00}, //H {0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00}, //I {0x00,0x7F,0x10,0x08,0x04,0x7F,0x00,0x00}, //N {0x7C,0x48,0x48,0xFF,0x48,0x48,0x7C,0x00} //中 }; void mDelay(uint Delay) { uint i; for(;Delay>0;Delay--) for(i=0;i<> } void display(uchar word_num) { //参数 word_num 就是要显示的排在数组第几位置的显示内容 uchar i; for(i=0;i<> { P2 = row[i]; //取出对应的行扫描控制信号 P0=word[word_num][i]; //取出对应的列扫描控制信号,显示内容 mDelay(1); //延时1毫秒(1秒=1000毫秒) P2=0xff; P0=0xff; } } 也就是说把几行常用的预定义#define命令,延时函数,显示函数,点阵数据全部放入头文件中,这样一来,主程序 就简单了,如下: #include “function.h” void main() { display(3); // 如此简单调用即可 } 也就是用一个命令#include 命令,把头文件 function.h 包括进来了 以后的学习也基本采用这种程序结构,模块功能放头文件function.h中,主程序更专注于自己要实现的功能。 |
|