大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
不知道这个是不是你要的
创新互联专注为客户提供全方位的互联网综合服务,包含不限于成都网站设计、做网站、申扎网络推广、微信小程序开发、申扎网络营销、申扎企业策划、申扎品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联为所有大学生创业者提供申扎建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com
//======================================================
// 文件名称: Clock.c
// 功能描述: 计时模块,使用2Hz时基中断
// 维护记录: 2006-08-30 v1.0
//======================================================
#include "spce061a.h"
typedef struct STR_CLOCK // 定义时钟结构体
{
unsigned int Year;
unsigned int Mon;
unsigned int Day;
unsigned int Hour;
unsigned int Min;
unsigned int Sec;
unsigned int HalfSec;
}CLOCK;
CLOCK Clock = {2006, 1, 1, 0, 0, 0, 0}; // 时钟初始值2006年1月1日0点0分
const unsigned int Month_Day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 每月包含的天数
//=============================================================
// 语法格式: void Clock_ISR(void);
// 实现功能: 计时模块的2Hz中断服务程序,应在IRQ5_2Hz中断中调用
// 参数: 无
// 返回值: 无
//=============================================================
void Clock_ISR()
{
if(Clock.HalfSec==0) // 0.5秒
Clock.HalfSec = 1;
else
{
Clock.HalfSec = 0;
Clock.Sec += 1;
if(Clock.Sec==60) // 处理秒进位
{
Clock.Sec = 0;
Clock.Min += 1;
if(Clock.Min==60) // 处理分进位
{
Clock.Min = 0;
Clock.Hour += 1;
if(Clock.Hour==24) // 处理小时进位
{
Clock.Hour = 0;
Clock.Day += 1; // 处理天进位
if(Clock.Day Month_Day[Clock.Mon-1])
{
if(Clock.Mon!=2 || (Clock.Year0x03)!=0 || Clock.Day29)
{ // 如果是闰年则2月29日不进位
Clock.Day = 1;
Clock.Mon += 1;
if(Clock.Mon 12) // 处理月进位
{
Clock.Mon = 1;
Clock.Year += 1;
}
}
}
}
}
}
}
}
//=============================================================
// 语法格式: void Clock_Start(void);
// 实现功能: 开始计时
// 参数: 无
// 返回值: 无
//=============================================================
void Clock_Start()
{
*P_INT_Ctrl_New |= C_IRQ5_2Hz;
__asm("IRQ ON");
}
//=============================================================
// 语法格式: unsigned int Clock_GetYear();
// 实现功能: 查询当前年
// 参数: 无
// 返回值: 当前年
//=============================================================
unsigned int Clock_GetYear()
{
return Clock.Year;
}
//=============================================================
// 语法格式: unsigned int Clock_GetMon(void);
// 实现功能: 查询当前月
// 参数: 无
// 返回值: 当前月
//=============================================================
unsigned int Clock_GetMon()
{
return Clock.Mon;
}
//=============================================================
// 语法格式: unsigned int Clock_GetDay(void);
// 实现功能: 查询当前日
// 参数: 无
// 返回值: 当前日
//=============================================================
unsigned int Clock_GetDay()
{
return Clock.Day;
}
//=============================================================
// 语法格式: unsigned int Clock_GetHour(void);
// 实现功能: 查询当前小时
// 参数: 无
// 返回值: 当前时
//=============================================================
unsigned int Clock_GetHour()
{
return Clock.Hour;
}
//=============================================================
// 语法格式: unsigned int Clock_GetMin(void);
// 实现功能: 查询当前分
// 参数: 无
// 返回值: 当前分
//=============================================================
unsigned int Clock_GetMin()
{
return Clock.Min;
}
//=============================================================
// 语法格式: unsigned int Clock_GetSec(void);
// 实现功能: 查询当前秒
// 参数: 无
// 返回值: 当前秒
//=============================================================
unsigned int Clock_GetSec()
{
return Clock.Sec;
}
//=============================================================
// 语法格式: void Clock_SetYear(unsigned int Year);
// 实现功能: 设置年
// 参数: Year - 年
// 返回值: 无
//=============================================================
void Clock_SetYear(unsigned int Year)
{
Clock.Year = Year;
}
//=============================================================
// 语法格式: void Clock_SetMon(unsigned int Mon);
// 实现功能: 设置月
// 参数: Mon - 月
// 返回值: 无
//=============================================================
void Clock_SetMon(unsigned int Mon)
{
Clock.Mon = Mon;
}
//=============================================================
// 语法格式: void Clock_SetDay(unsigned int Day);
// 实现功能: 设置日
// 参数: Day - 日
// 返回值: 无
//=============================================================
void Clock_SetDay(unsigned int Day)
{
Clock.Day = Day;
}
//=============================================================
// 语法格式: void Clock_SetHour(unsigned int Hour);
// 实现功能: 设置小时
// 参数: Hour - 时
// 返回值: 无
//=============================================================
void Clock_SetHour(unsigned int Hour)
{
Clock.Hour = Hour;
}
//=============================================================
// 语法格式: void Clock_SetMin(unsigned int Min);
// 实现功能: 设置分
// 参数: Min - 分
// 返回值: 无
//=============================================================
void Clock_SetMin(unsigned int Min)
{
Clock.Min = Min;
}
//=============================================================
// 语法格式: void Clock_SetSec(unsigned int Sec);
// 实现功能: 设置秒
// 参数: Sec - 秒
// 返回值: 无
//=============================================================
void Clock_SetSec(unsigned int Sec)
{
*P_TimeBase_Clear = 0x01; // 时基计数器清零
Clock.Sec = Sec;
Clock.HalfSec = 0; // 半秒计数清零
}
#include
"spce061a.h"
//功能:IOA接LED灯,低电平亮,高电平灭。每隔1S闪烁1次
void
IRQ5(void)
__attribute__
((ISR));//4HZ中断在IRQ5里面
unsigned
int
count_1s=0;//1秒计数
int
main()
{
__asm("INT
OFF");//关闭总中断
*P_IOA_Dir=0xffff;//IOA为输出
*P_IOA_Attrib=0xffff;//IOA为无反相
*P_IOA_Data=0xffff;//先初始化输出1
*P_INT_Ctrl=C_IRQ5_4Hz;//允许4HZ中断
__asm("INT
IRQ");//打开IRQ总中断
while(1)
{
*P_Watchdog_Clear=1;//不停清狗,等待中断
}
return
0;
}
void
IRQ5(void)//IRQ5中断包含2HZ中断和4HZ中断
{
if((*P_INT_Ctrl)C_IRQ5_4Hz)//判断是否由4HZ引起的中断
{
if(++count_1s==4)//是否进入4次中断了?
{
count_1s=0;//计数清零
*P_IOA_Data^=0xffff;//IOA取反,使得LED灯闪烁
}
*P_INT_Clear=C_IRQ5_4Hz;//清除4HZ中断标志
}
else//否则是由2HZ引起的。(该else可以不用写的,因为之前没有允许2HZ中断,所以IRQ5必然是因4HZ中断进入)
{
*P_INT_Clear=C_IRQ5_2Hz;//没用到2HZ,直接清除2HZ中断标志
}
}
也是一个led网站
摘 要
本系统是从实际应用角度出发,针对当前市场上流行的LED产品的应用领域而设计制作的多功能电子显示屏,可用于商场导购促销显示、新闻与广告显示、车站机场班次时间资讯显示等。
本简易16行*64列LED电子显示屏根据题目设计要求,硬件部分主要包括SPCE061A单片机系统、16块8*8LED点阵显示模块构成16*64点阵、显示驱动电路、SPR4096存储器、PCF8563实时时钟电路、键盘输入控制器等部分,还外扩了液晶显示、温度实时检测、无线通讯、电机驱动屏幕旋转等电路,。本系统不仅能够实现数字、字母、汉字等预存信息的切换显示,同时还可以实现信息的定时循环、上下左右滚屏、LED显示亮度连续可调、实时时间显示、实时温度显示、无线遥控、显示屏旋转等扩展功能。另外,本系统可以和PC机通讯,通过PC机串口对显示信息进行更新。
关键词:LED电子显示屏 SPCE061A 串行通信
Abstract
The LED lattice display system is a kind of new information display media with the rapid development of the computer, micro-electronics, photoelectron technology.
This 16*64 LED display system includes SPCE061A MCU system, sixteen 8*8 LED lattice modules, display driving circuit, SPR4096 memory module, PCF8563 as the real-time clock chip, keyboard controller et. In addition, it includes LCD circuit, real-time temperature detective, RF communication circuit. This system can display the numbers, letters, Chinese characters. It can display the information timely and circularly, up-rollingly, down rollingly left-rollingly, right-rollingly. The lightness of the displaying information can be adjusted continuously. Further more, this system can be remote controlled and communicate with PC by COM1 to update the display information.
Keywords: LED lattice display system SPCE061A serial communication
目 录
一、方案比较 4
1、控制系统 4
2、点阵信息提取方案 4
3、显示驱动电路 5
二、硬件设计与论证 5
1、主控制单片机 6
2、LED显示驱动电路 6
3、数据存储器 8
4、键盘液晶显示模块 9
5、无线通信模块 9
6、时钟电路的设计 10
7、温度检测 10
8、打印机的选择 11
9、旋转底盘的设计 11
三、系统的软件设计 11
1、主程序流程图 12
2、点阵字模信息提取程序流程图 12
3、LED各显示程序 12
4、串行通信程序 12
5、PC机客户程序 12
四、系统功能测试 16
1、测试及制作中所用仪器 16
2、键盘各键功能 16
3、单元模块电路测试 16
4、系统整体功能测试 16
五、总结 17
一、方案比较
1、控制系统
LED点阵电子显示屏的设计一般有两种方案:
方案一:采用可编程逻辑器件作为核心控制器产生LED点阵的行、列驱动信号。由于该系统不仅要实现信息的显示,还要具备键盘控制器、显示亮度连续可调、实时时钟显示、与PC机通讯等功能及其他发挥功能,这就要求需要用中大规模的PLD,设计多个接口电路,开发周期长,不易进一步扩展,同时系统的成本会急剧上升(相对于第二种方案)。因此,本设计并未采用这种方案。
方案二:采用单片机系统来实现。鉴于SPCE061A单片机比传统的51系列8位单片机具有更加丰富的资源,而且数据处理速度快,同时“61板除了具备单片机最小系统电路外还包括有电源电路、音频电路(含MIC输入部分和DAC音频输出部分)、复位电路等,体积小,可靠性高。本系统的设计采用双单片机系统,一个主要用于完成多功能显示控制功能,另一个主要用于实时时钟显示、实时温度检测显示、无线通讯以及其他的扩展发挥部分功能,这样提供了充足的内部空间和更多的外部接口;同时由于安装和调试工作可以并行进行,极大地缩短了总体设计和制造的时间。
2、点阵信息提取方案
要用LED点阵来显示数字、字母和汉字等信息,首先要能够提取出其字模数据,即一个16*8的点阵数字、字母的字模数据共有16个字节,一个16*16的点阵汉字的字模数据共有32个字节。首先要确定点阵信息提取方案。
方案一:固定汉字显示,就是将要显示的语句中全部汉字的字母数据依次提取出来,按顺序存放在存储器中,当有显示任务时,直接取出字模数据送至显示器即可。这种方法占用空间少,程序实现简单,显示速度快。本系统中对10组预存信息的点阵信息的提取和存储就是采用这种方案。但是,要想显示大量的汉字信息或直接对显示信息进行更新,则几乎是不可能的事。因此,要实现这样的功能就要采用第二种方案。
方案二:将标准的点阵信息字模数据的字库文件(本系统中采用汉字库文件HZK16、ASCII码库文件ASC16)装入外扩ROM存储器,采用与PC机相同的编码(机内码),先进行基于PC机的预处理,提取需显示内容的机内码,通过串口发给单片机,单片机首先进行判断,若是ASCII码,则直接计算出起始地址,在ASC16文件中指定位置取出连续的16个字节即为其字模信息;若为汉字,单片机将机内码转换为区码和位码,再计算出起始地址,在HZK16文件中指定位置取出连续的32个字节即为其字模信息,然后送到显示器去显示。另外,PC机与单片机之间串口通信只是传输机内码,而不是传输字模信息,传输信息量小,不需要复杂的通信协议。这样既可以减轻单片机的负担,而且可以根据要求随时改变显示内容,非常简单灵活。
3、显示驱动电路
常用的显示驱动方式有三种:
方案一:串行控制驱动,这种方式的好处是单元内的线路连接简单,给印刷电路板的设计带来方便,减少了布线的密度,方便以后的制作与调试,而且相对提高了每个单元的可靠性;
方案二:并行控制驱动,将显示数据通过并行(一般为8位)方式送入驱动电路,这样的好处是:相对于串行控制而言,数据的刷新速度快,在处理同等数量的数据时,对处理速度要求可以大大降低,从而提高了系统的稳定性,但也正因为“并行”使单元内的数据线路的连接更加复杂,布线后的排错难度大大增加;
方案三:采用专用集成电路(ASIC)直接驱动,由于这种专用集成电路是集行控制、列控制和外围驱动于一体,使系统的稳定性更为可靠,特别适合户外的大型或者超大型显示屏。因为这种类型的显示屏对图像显示要求高,不仅要保证图像的一致性,而且要保证图像的稳定、高亮。
本次设计的显示屏仅为16行*64列,更适合采用串行控制这种方式,这样做既省去了并行控制驱动在制版过程中十分复杂的布线,又因为没有采用专用集成电路在一定程度上降低了整个系统的成本。
二、硬件设计与论证
根据以上的系统方案比较与分析,本设计的系统总体组成框图如图1所示:
图1 系统的总体组成框图
系统整体由三大部分构成:
以单片机1#为核心的模块一:包括16*64LED点阵、驱动电路、STR4096存储器、无线数传模块、旋转底盘、光电传感器、音箱、打印机。实现功能:主要用来实现点阵的显示,包括特定标语库内容的显示,适时时间显示、适时温度显示,并实现上下左右滚屏等各种花样显示;存储器用来存储汉字和ASCII码的点阵库,并实现掉电不丢失功能;无线模块实现标语库更新和接受设置信息;底盘可实现显示屏的左右转动,摆动幅度可调;在商场导购中,光电传感器用于检测人员进出,可与自动门配合使用,音箱播放“欢迎光临”等语音信息;在广告牌应用中,打印机用于名片打印。
以单片机2#为核心的模块二:包括4*4键盘、液晶、无线数传模块。实现功能:该部分实现遥控器的功能,可以遥控设置显示屏的滚动模式,选择标语库,设置时间,设置摆头幅度;实现标语库的更新。(键盘使用说明见附录一)
以上位PC机为核心的模块三:包括上位机软件和MAX232。实现功能:上位机主要实现标语库的数据更新,上位机软件通过MAX232将更新内容(汉字或者ASCII码的机内码)送到单片机2#,然后无线传输到单片机1#实现数据更新。
以下是各单元电路的具体设计:
1、主控制单片机
采用凌阳公司的16位单片机SPCE061A作为主控制器。由于SPCE061A内置有2K字的SRAM和32K字的内存FLASH,能满足本系统数据处理及LED点阵显示所需数据的存储要求;CPU时钟频率高达49.152MHz,能满足刷新速度要求。另外,“61板”功能较强、性价比高,具有体积小、集成度高、易扩展、功耗小等优点,简化主控制系统的硬件电路设计,可靠性高,而且凌阳单片机具有C语言风格的汇编语言,有与标准C兼容的C语言,C语言函数可以与汇编函数互相调用,使其开发更加容易,实现整个系统更加简单。
2、LED显示驱动电路
本次设计中16行*64列LED电子显示屏的制作以及其显示驱动电路的设计制作都是非常关键的部分。下面主要介绍一下显示驱动电路的设计。
本LED点阵屏采用动态扫描的方式显示,即逐行扫描,工作时先将一行点阵字模通过列驱动输出,然后运用译码器选中对应行,使该行得以显示,接着再送下一行数据,再选中下一行有效,直到16行全被扫描一遍。至此,一幅完整的文字信息就显现出来。然后在反复扫描这16行直至显示新的信息。采用这种方式的优点是耗电少,成本低,寿命长,但是也存在显示亮度及内容显示稳定的问题。根据视觉滞留原理,根据视觉滞留原理,每屏的完整的显示时间应控制在20ms之内,即50Hz,人眼看上去才不会觉得闪烁。由于要扫描16 行的点阵,所以每行的时间绝不能超过20ms÷16=1.25ms,同时也不是每行的扫描时间越短越好,因为LED的亮度同电流的大小和维持时间的长短有关。LED点阵块的单点静态电流一般在10mA左右,由于占空比是1/16,所以单点的动态电流最大可以达到160mA。在维持时间恒定的情况下,电流越大(不超过额定电流),点阵亮度也越亮,而在电流恒定的情况下,需要一段维持时间来保持亮度。试验表明当输入LED的电流为15mA时,维持时间至少需要1ms,否则LED呈微亮状态。由于设计时设置SPCE061A单片机的时钟频率为24MHz,而每次传送移行的字模数据有64位,经计算传输所需的时间小于1ms,这样就能充分利用列驱动74HC595的锁存功能,即在它接收下一行待显示的数据,还没有锁存新数据的这段时间来显示本行的内容,这样就不需要额外加延时来增加显示屏的亮度。采用这个方法就不要再增加LED的列驱动器件,从而使整个硬件结构更简化,成本降低。
行信号的处理是由四十六译码器CD4514来完成译码,输出为高。由于显示屏行的组成是多个模块并联而成的,因而行驱动得功率要求比较大,而且我们进行行扫描时需要所选行为低,故加反相驱动器ULN2803来满足要求。
列信号的处理列信号的处理主要由8片8位带锁存的串入并出移位寄存器74HC595来完成。从单片机IO口串行输出的64位点阵数据随着移位时钟的作用逐位移动到对应位置,在接收到锁存信号后,将数据并行输出至LED的列线,最后在行驱动信号作用下点亮一行LED象素。
显示扫描电路的电路图如图2所示。
图2 LED显示扫描驱动电路
3、数据存储器
设计题目要求能增大到10组预存信息,且显示信息具有掉电保护功能,同时考虑到要把汉字点阵字库文件HZK16(261K字节)和ASCII码点阵字库文件ASC16(4K字节)装入到ROM存储器中,以便根据机内码在字库中寻址,找到对应的字模,提取后再送到点阵显示屏显示。因为SPCE061单片机的内存Flash只有32K,还要存放程序,因此需外扩数据存储器。我们选择了凌阳“61板”的配套模组SPR4096。SPR4096是一个高性能的4M-bit(512K字节)FLASH,分为256个扇区,每个扇区为2K字节。SPR4096串行接口的工作频率可达5MHz,数据存取速度和存储容量都能够达到我们的要求。硬件图连接如图3所示:
图3 SPR4096硬件连接图
4、键盘液晶显示模块
为使用键盘作为显示屏控制器,实现多功能显示控制,我们使用智能型键盘显示控制芯片HD7279A作为4*4键盘与单片机之间的接口,其与微处理器仅需4条接口线,采用串行通信方式,占用CPU端口少,同时HD7279得到键盘码后通过中断服务程序把按键信息送给单片机,使单片机可以腾出更多时间质性其他操作。设计中我们需要用液晶模块显示遥控单片机菜单的各信息。在本系统中选用了OCM4×8C模块,可以显示字母、数字符号、中文字型及图形,具有绘图及文字画面混合显示功能,既可采用并行接口,又可采用串行接口,连线较为方便。HD7229、OCM4×8C与单片机连接原理图如图4所示。
5、无线通信模块
在本设计中,我们采用了两块61板,1#板主要用于完成控制LED显示屏,2#板主要用于键盘液晶控制、实时时钟、实时温度检测显示、与PC机通讯以及其他的扩展发挥部分功能。两板之间采用无线通讯进行数据传输。为满足系统的要求我们选择了SRWF-1型微功率无线数传模块,该模块的特点是:高抗干扰能力和低误码率、完善的通讯协议、数据实时同步、看门狗实时监控、传输距离远、低功耗及休眠功能高可靠性,体积小、重量轻。
图4 键盘显示电路
SRWF-1型模块提供2个串口3种接口方式,COM1为TTL电平UART接口,COM2由用户自定义为标准的RS-232/RS-485接口(用户只需拔/插短路器再上电即可改变接口类型)。SRWF-1提供的两个串口,在使用时注意以下事项:(1)对于空中接收的数据,SRWF-1通过串口转送给终端设备时,COM1和COM2同时输出,即用户如果在COM1和COM2各连接了1个设备,他们都可同时收到数据;(2)对于由终端设备送来,准备向空中发射的数据,SRWF-1只能正确接收COM1或COM2其中1个串口送来的数据,否则将造成数据通讯混乱。如终端设备在向COM1发送1个0x12(数据正在传送)时,再向COM2发送1个0x34,模块将收到一个数据串0x12,0x34。
图5 SRWF-1与用户设备接口电路
注:没有使用的引脚可以悬空不连。但不能连接长悬空线,以免引入干扰。
6、时钟电路的设计
系统要求实现实时时间的显示,这里我们选用串行日历时钟芯片PCF8563,,与单片机的连线大为减少,极大的节省了单片机的系统资源。PCF8563与单片机的接口电路如图6所示。而且该部分电路还加了掉电保护功能,在主供电系统意外断电时,即Vcc为0V时,D1截止, 3.6V备用电源通过D2继续给PCF8563供电,保证8563的正常运行。
图6 PCF8563时钟电路
7、温度检测
本系统扩展了实时温度检测显示功能,选用DS18B20一线式数字温度传感器,通过单片机读取当前环境温度可通过键盘切换显示时间和温度。
图6 DS18B20与单片机的接口电路
8、打印机的选择
本系统还扩展了打印机功能,在广告牌应用中用来打印名片等相关信息。我们选择了北京市兴伟机电应用技术研究所研制的微型热敏/针打打印机。通过通用的ESC/P打印命令实现字符的打印。
图7 打印机接口控制时序图
9、旋转底盘的设计
针对应用的需要,系统扩展了显示屏旋转功能,用普通小型直流电机提供动力,由变速箱减速并加大驱动能力,实现显示屏幕左右摆动,并且幅度可调。
图8 直流电机驱动电路
三、系统的软件设计
本系统的软件部分主要包括主程序、点阵字模信息提取程序、LED各显示程序、串行通信程序以及PC机客户程序等。
1、主程序流程图
见图8。
2、点阵字模信息提取程序流程图
见图9。
3、LED各显示程序
LED显示屏的显示方式有静止、上下滚屏、左右滚屏等多种方式。其中上下滚屏显示程序类似,左右滚屏显示程序类似,其他多花样的显示方式程序都是在此基础上进行改动而来的。因此主要给出静态显示、上移显示、左移显示这三种典型方式的程序流程图,见图10、图11、图12。
4、串行通信程序
每当向PC机客户程序里输入新显示内容并发送给单片机时,单片机就产生串行中断,接受待显示信息的机内码,然后再利用点阵字模信息提取程序得到点阵数据送到LED显示屏显示。单片机接受数据采用中断的方式。串行中断程序流程图见图13。
5、PC机客户程序
本系统的PC机客户程序是采用Visual Basic 6.0进行开发的,主要利用其串行通信控件MSComm,其主要流程图及运行效果见图14、图15。
图8 主程序流程图 图9 点阵字模信息提取程序流程图
图10 静态显示程序流程图 图11 上移显示程序流程图
图12 左移显示程序流程图
图13 串行中断程序流程图 图14 PC机客户程序流程图
图15 PC机客户控制程序的界面
四、系统功能测试
1、测试及制作中所用仪器
GDS-820C型双踪数字示波器、UNT-T型台式数字万用表、
SK1731SL2A直流稳压电源、F10型数字合成函数信号发生器、
联想PC、烙铁等
2、键盘各键功能
1 2 3 4
5 6 7 8
9 0 ./+ C/-
确定 上 下 取消
“0—9” :数字键;
“. /+” :小数点/数据加1;
“C/-” : 删格/数据减1;
“确定” :进入菜单,保存设置
“取消” :返回上一级菜单
“上” : 菜单上翻,插入点左移
“下” : 菜单下翻,插入点右移
3、单元模块电路测试
1)LED点阵测试:用程序实现所有点阵全部点亮,显示部分点阵块无法完全点亮,更换点阵块后显示正常。
2)无线数传测试:由单片机#2无线发送1000字节数据,单片机#1接收并存储,通过开发环境查看接收数据,发送一百次,成功接收100次,经测试系统稳定;
3)与上位机通信测试:上位机循环发送1000字节数据,单片机接收并校验,接受成功后送液晶显示,然后停止发送,经测试接收时间相对于人的反映时间可以忽略。测试20次,成功接受20次。
4)键盘液晶测试:用键盘控制菜单进出,上下翻页,键盘无抖动,液晶无闪烁。
4、系统整体功能测试
各单元模块整合后,系统上电,显示屏上显示预存信息,通过2#机上的键盘可以成功控制1#机上的显示,包括预存信息切换显示、翻页、上下滚屏、左右滚屏、对流、展开等各花样显示方式、LED显示屏亮度连续可调,能成功地显示出字母、数字、汉字等信息,通过按键可以控制显示实时时间、实时温度等信息,而且断电后,重新开机,预存的显示信息与时间均可掉电保护。通过PC机的客户程序发送需更新信息数据到2#机,由2#机通过无线数传模块发送给1#机,可以成功地更新显示内容。
经过多次测试,整个系统工作稳定可靠,能够实现上述所有功能。
五、总结
我们制作的这套LED点阵电子显示屏系统不仅完成了题目要求的基本功能和发挥功能,还在实时温度检测显示、无线遥控、显示方式等方面有所创新。本系统以凌阳16位单片机SPCE061A为核心部件,最终完成了竞赛题目中要求的各项任务,包括可以控制16*64LED点阵显示屏实现信息的左右滚屏、显示屏亮度连续可调、实时时间和实时温度的显示等,在设计过程中,力求硬件线路简单,充分发挥软件在编程方面灵活的特点,来满足系统设计的要求。
在竞赛的过程中,我们遇到了许多突发性的不太好解决的问题,例如,在整个系统的调试过程中,我们体会到无论是硬件还是软件的调试都要注意模块化,要从最底层开始,逐级通过后才能进行下一步的工作;同时在联合调试的过程中,应注意各模块之间的时序配合问题,有时都是正确的模块程序却因为按照不恰当的顺序来执行从而导致程序运行结果完全出错。
通过这次比赛,我们深深的体会到了团队间的共同协作的重要性,提高了自己的动手能力和解决问题的能力。
#include "SPCE061A.h"
#include "ultrasonic_App.h"
//========================================================================
// 语法格式: int main(void)
// 实现功能: 主程序
// 参数: 无
// 返回值: int 无意义
//========================================================================
void F_Key_Scan_Initial(void);
void F_Key_Scan_ServiceLoop(void);
unsigned int SP_GetCh(void);
void Speech_Resource(unsigned int iSpeechIndex);
void Speech_Result(unsigned int uiResult);
int main(void)
{
unsigned int uiKey;
unsigned int Back_data;
F_Key_Scan_Initial();
Initial_ult();
while(1)
{
uiKey = SP_GetCh();
switch(uiKey)
{
case 0: break;
case 1:
Back_data = measure_Times(1);
if(Back_data==0)
Speech_Resource(12); //结果为0时表示测量出错,播放"咚"
else
Speech_Result(Back_data);
break;
case 2:
break;
case 3: break;
default: break;
}
F_Key_Scan_ServiceLoop();
*P_Watchdog_Clear = 0x0001;
}
}
//========================================================================
// 文件名称: IRQ.c
// 功能描述: IRQ中断服务程序
// 维护记录: 2006-04-13 V2.0
//========================================================================
#include "SPCE061A.h"
#include "ultrasonic_App.h"
void IRQ3(void)__attribute__((ISR));
void IRQ3(void)
{
*P_INT_Clear = 0x0100; //
EXT1_IRQ_ult(); //调用超声波测距的外部中断服务程序
}
//========================================================================
// 文件名称: ultrasonic_App.c
// 功能描述: 超声波测距模组V2.0的功能接口函数
// 维护记录: 2006-02-21 V2.0
//========================================================================
#include "SPCE061A.h"
#define LONG_SEND_TIMER 1000 //中距测距时的40KHz信号发射时长
#define LONG_SEND_TIMER2 3000 //中距测距的补充测距时的40KHz信号发射时长
#define LONG_WAIT_DELAY 600 //中距测距的防余波干扰延时时长
#define LONG_WAIT_DELAY2 1500 //中距测距的补充测距时的防余波干扰延时时长
#define LONG_RES_ADD 0x00B0 //中距测距的结果补偿值
#define LONG_RES_ADD2 0x0220 //中距测距的补充测距时的结果补偿值
#define LOW_SEND_TIMER 250 //短距测距时的40KHz信号发射时长
#define LOW_SEND_TIMER2 1000 //短距测距的补充测距时的40KHz信号发射时长
#define LOW_WAIT_DELAY 180 //短距测距的防余波干扰延时时长
#define LOW_WAIT_DELAY2 400 //短距测距的补充测距时的防余波干扰延时时长
#define LOW_RES_ADD 0x0034 //短距测距的结果补偿值
#define LOW_RES_ADD2 0x00B0 //短距测距的补充测距时的结果补偿值
unsigned int Counter_buf; //超声波测距当中,用于保存TimerB计数的变量,相当于时长
unsigned int EXT1_IRQ_flag=0; //外部中断标志变量,用于EXT1的IRQ中断程序和测距程序同步
//========================================================================
// 语法格式: void Initial_ult(void)
// 实现功能: 超声波测距模组的初始化子程序
// 参数: 无
// 返回值: 无
//========================================================================
void Initial_ult(void)
{
unsigned int uiTemp;
// 初始化端口主要是IOB8和IOB9
uiTemp = *P_IOB_Dir;
uiTemp = uiTemp|0x0200;
uiTemp = uiTemp0xfeff;
*P_IOB_Dir = uiTemp;
uiTemp = *P_IOB_Attrib;
uiTemp = uiTemp|0x0200;
uiTemp = uiTemp0xfeff;
*P_IOB_Attrib = uiTemp;
uiTemp = *P_IOB_Buffer;
uiTemp = uiTemp|0x0300;
*P_IOB_Data = uiTemp;
}
//========================================================================
// 语法格式: void Delay_ult(unsigned int timers)
// 实现功能: 超声波测距模组的延时子程序
// 参数: unsigned int timers 延时的时长(仅是一个相对量)
// 返回值: 无
//========================================================================
void Delay_ult(unsigned int timers)
{
unsigned int i;
for(i=0;itimers;i++)
{
__asm("nop");
}
}
//========================================================================
// 语法格式: unsigned int Resoult_ult(unsigned int Counter)
// 实现功能: 超声波测距模组的测距数据处理程序,将TimerB的计数值换算为距离
// 参数: Counter 需要换算的计数值
// 返回值: 计算后的距离,厘米为单位
//========================================================================
unsigned int Resoult_ult(unsigned int Counter)
{
unsigned int uiTemp;
unsigned long ulTemp;
ulTemp = (unsigned long)Counter*33500;
ulTemp = ulTemp/196608;
ulTemp = ulTemp1; //除二
uiTemp = (unsigned int)ulTemp;
return uiTemp;
}
//========================================================================
// 语法格式: unsigned int measure_ult(unsigned int type)
// 实现功能: 超声波测距模组的测距程序,完成一次测距
// 参数: type 选择测距类型,
// type=1 中距测距
// type=0 短距测距
// 返回值: 所测得的距离,以厘米为单位
//========================================================================
unsigned int measure2_ult(unsigned int type);
unsigned int measure_ult(unsigned int type)
{
unsigned int Exit_flag = 1;
unsigned int uiTemp;
unsigned int uiResoult;
unsigned int uiSend_Timer,uiWait_Timer,uiRes_Add;
unsigned int uiSystem_Clock;
uiSystem_Clock = *P_SystemClock; //将当前的系统时钟设置暂时保存起来
*P_SystemClock = 0x0088; //将系统时钟设置为49MHz,分频比为1,强振模式
if(type) //根据type即测距类型,选择不同的测距参数
{
uiSend_Timer = LONG_SEND_TIMER;
uiWait_Timer = LONG_WAIT_DELAY;
uiRes_Add = LONG_RES_ADD;
}
else
{
uiSend_Timer = LOW_SEND_TIMER;
uiWait_Timer = LOW_WAIT_DELAY;
uiRes_Add = LOW_RES_ADD;
}
*P_TimerB_Data = 0xfed2;
*P_TimerB_Ctrl = 0x03c0; //enable 40KHz out
Delay_ult(uiSend_Timer); //delay for send the signal
*P_TimerB_Ctrl = 0x0006; //stop 40KHz out
*P_TimerB_Data = 0x0000;
*P_TimerB_Ctrl = 0x0001; //TimerB work as a counter at 192KHz
while(*P_TimerB_DatauiWait_Timer) //等待一定时间后再打开TimerA的计数(来源于EXT1)
{ //以避开余波的干扰
*P_Watchdog_Clear = 0x0001;
}
*P_INT_Clear = 0x0100; //开中断前先清中断
*P_INT_Ctrl = *P_INT_Ctrl_New|0x0100;
*P_INT_Clear = 0xffff; //清除中断发生标志
__asm("IRQ ON"); //打开总中断使能
EXT1_IRQ_flag = 0; //TimerA的溢出中断的标志变量置0
while(Exit_flag)
{
if(EXT1_IRQ_flag==1) //当该变量在timerA的FIQ中断中被置1时表示接收到了回波
{
Exit_flag = 0; //exit
Counter_buf = Counter_buf+uiRes_Add;//计数值加上一定的调整数据
uiResoult = Resoult_ult(Counter_buf);//对计数值进行处理,得出距离值
}
if(*P_TimerB_Data10000) //如计数值大于10000,表示超时
{
Exit_flag = 0; //exit
uiResoult = measure2_ult(type);//再进行一次补充的测距,将会加长40KHz信号发射的量
*P_TimerB_Ctrl = 0x0006; //stop timerB
}
uiTemp = *P_TimerB_Data;
*P_Watchdog_Clear = 0x0001;
}
*P_INT_Ctrl = *P_INT_Ctrl_New(~0x0100); //关掉外部中断
__asm("IRQ OFF"); //关掉总中断
*P_SystemClock = uiSystem_Clock; //恢复系统时钟的设置
return uiResoult;
}
//========================================================================
// 语法格式: void EXT1_IRQ_ult(void)
// 实现功能: 超声波测距模组的测距程序的EXT1中断服务程序,在EXT1的IRQ中断
// 中调用
// 参数: 无
// 返回值: 无
//========================================================================
void EXT1_IRQ_ult(void)
{
Counter_buf = *P_TimerB_Data; //save the timerB counter
*P_TimerB_Ctrl = 0x0006; //stop timerB
*P_INT_Ctrl = *P_INT_Ctrl_New(~0x0100); //关掉外部中断
*P_INT_Clear = 0xffff; //清除中断发生标志
EXT1_IRQ_flag = 1; //通知测距程序,外部中断已发生
}
//========================================================================
// 语法格式: unsigned int measure2_ult(void)
// 实现功能: 补充进行一次远距的测量,以保证能够获取测量结果
// 参数: type 选择测距类型,
// type=1 中距测距
// type=0 短距测距
// 返回值: 所测得的距离,以厘米为单位
//========================================================================
unsigned int measure2_ult(unsigned int type)
{
unsigned int Exit_flag = 1;
unsigned int uiResoult;
unsigned int uiSend_Timer,uiWait_Timer,uiRes_Add;
*P_TimerA_Ctrl = 0x0006; //stop TimerA
*P_INT_Ctrl = *P_INT_Ctrl_New(~0x0100); //关掉外部中断
__asm("IRQ OFF"); //关掉总中断
*P_INT_Clear = 0xffff; //清除掉中断发生标志
if(type) //根据type即测距类型,选择不同的测距参数
{
uiSend_Timer = LONG_SEND_TIMER2;
uiWait_Timer = LONG_WAIT_DELAY2;
uiRes_Add = LONG_RES_ADD2;
}
else
{
uiSend_Timer = LOW_SEND_TIMER2;
uiWait_Timer = LOW_WAIT_DELAY2;
uiRes_Add = LOW_RES_ADD2;
}
*P_TimerB_Data = 0xfed2;
*P_TimerB_Ctrl = 0x03c0; //enable 40KHz out
Delay_ult(uiSend_Timer); //delay for send the signal
*P_TimerB_Ctrl = 0x0006; //stop 40KHz out
*P_TimerB_Data = 0x0000;
*P_TimerB_Ctrl = 0x0001; //TimerB work as a counter at 192KHz
while(*P_TimerB_DatauiWait_Timer) //等待一定时间,以避开余波的干扰
{
*P_Watchdog_Clear = 0x0001;
}
*P_INT_Ctrl = *P_INT_Ctrl_New|0x0100;//打开外部中断
*P_INT_Clear = 0xffff; //清除中断发生标志
__asm("IRQ ON"); //打开总中断使能
EXT1_IRQ_flag = 0; //TimerA的溢出中断的标志变量置0
while(Exit_flag)
{
if(EXT1_IRQ_flag==1) //当该变量在timerA的FIQ中断中被置1时表示接收到了回波
{
Exit_flag = 0; //exit
Counter_buf = Counter_buf+uiRes_Add;//计数值加上一定的调整数据
uiResoult = Resoult_ult(Counter_buf);//对计数值进行处理,得出距离值
}
if(*P_TimerB_Data10000) //如计数值大于10000,表示超时
{
Exit_flag = 0; //exit
uiResoult = 0; //error return data 0
*P_TimerB_Ctrl = 0x0006; //stop timerB
}
}
return uiResoult;
}
//========================================================================
// 语法格式: unsigned int measure_Times(unsigned int type)
// 实现功能: 组合进行共6次的测距程序,包括对6次测量结果的取平均值处理
// 参数: type 选择测距类型,
// type=1 中距测距
// type=0 短距测距
// 返回值: 所测得的距离,以厘米为单位
//========================================================================
unsigned int measure_Times(unsigned int type)
{
unsigned int uiResoult=0,uiMeasure_Index=0,i;
unsigned int uiTemp_buf[6],uiTemp;
unsigned int uiSystem_Clock;
for(;uiMeasure_Index6;uiMeasure_Index++)
{ //循环进行四次测量
uiTemp = measure_ult(type); //进行一次测量,测量类型由type决定
if(uiMeasure_Index==0) //如果为本次测量的第一次测距,则直接保存在缓冲区第一个单元
uiTemp_buf[0] = uiTemp;
else
{ //否,则对结果进行比较,进行排序,从大到小排
i = uiMeasure_Index;
while(i) //以下为排序的代码
{
if(uiTempuiTemp_buf[i-1])
{
uiTemp_buf[i] = uiTemp_buf[i-1];
uiTemp_buf[i-1] = uiTemp;
}
else
{
uiTemp_buf[i] = uiTemp;
break; //退出排序
}
i--;
}
}
//两次测量之间的延时等待,利用以下代码软仿真时的cycles数结合设置的CPUCLK进行计算,大概72ms
uiSystem_Clock = *P_SystemClock; //将之前的系统时钟的设置用变量保存
*P_SystemClock = 0x000b; //设置为FSYS=24.576MHz 分频比为8
for(i=0;i5;i++)
{
Delay_ult(1000); //调用延时程序
*P_Watchdog_Clear = 0x0001;
}
*P_SystemClock = uiSystem_Clock; //恢复系统时钟设置
//此处延时结束
}
//对6次测距的结果进行处理
if(uiTemp_buf[5]==0)
{ //如果缓冲区中的最小的测距值为0,则采用中间4个数据进行平均
uiResoult = uiTemp_buf[1]+uiTemp_buf[2]+uiTemp_buf[3]+uiTemp_buf[4];
uiResoult = uiResoult/4;
}
else
{ //否则就取后5个数据进行平均
uiResoult = uiTemp_buf[1]+uiTemp_buf[2]+uiTemp_buf[3]+uiTemp_buf[4]+uiTemp_buf[5];
uiResoult = uiResoult/5;
}
return uiResoult;
}
这几天在学习凌阳单片机,这个单片机是16位的,性能比51单片机强多了。可是在网上却没有多少这方面的例程,特别是C语言例程,让我感觉很是无奈。于是特发一些凌阳单片机的一些我自己编写的程序。虽然很简单,可是也能给一些准备学凌阳单片的人一点启发吧。 //==================================================================== //名称:流水灯 //功能描述:基于凌阳十六位单片单片机C语言实现IOA口的流动LED,位移动 // 先从左往右依次点亮,然后再从右往左依次点亮 //作者:杨勇 时间:2008年8月24日1:07:06 //版本:1.0 修改时间:2008年8月24日1:07:09 2008年8月25日1:29:02 //==================================================================== #include SPCE061A.H #define uint unsigned int //==================================================================== //函数名:主函数 //功能描述:控制整个系统的运行,实现IOA的流动LED //==================================================================== void main() { uint i,j; *P_IOA_Dir=0xffff; //定义IOA口为同向输出,并输出高电平 *P_IOA_Attrib=0xffff; *P_IOA_Data=0x0000; while(1) { *P_IOA_Data=0x8000; //点亮最高位LED for(j=0;j16;j++) //通过循环,从高到低位,依次点亮LED { *P_IOA_Data=1; for(i=0x0000;i0xffff;i++)//延时,并在延时器件清看门狗 { *P_Watchdog_Clear=0x0001; } } *P_IOA_Data=0x00001; for(i=0;i16;i++) //通过循环,从低到高位,依次点亮LED { *P_IOA_Data=1; for(j=0x0000;j0xffff;j++)//延时,并在延时器件清看门狗 { *P_Watchdog_Clear=0x0001; } } } }