51单片机入门经典教程


Maplead MCU Development Board http://shop63914145.taobao.com 1 目录 概述.............................................................................................................1 1.流水灯 ................................................................................................13 流水灯原理.............................................................................................................................13 开发板流水灯实物图.............................................................................................................13 流水灯演示程序.....................................................................................................................14 2.数码管 ................................................................................................15 数码管原理.............................................................................................................................15 8 段数码管编码......................................................................................................................15 数码管显示方式.....................................................................................................................16 开发板数码管实物图.............................................................................................................18 数码管演示程序.....................................................................................................................18 3.总线扩展技术 ....................................................................................21 总线扩展.................................................................................................................................21 74HC138.................................................................................................................................21 74HC573.................................................................................................................................22 开发板 74HC138 与 74HC573 实物图..................................................................................23 4.键盘 ....................................................................................................24 独立键盘.................................................................................................................................24 独立键盘演示程序.................................................................................................................25 矩阵键盘.................................................................................................................................26 矩阵键盘演示程序.................................................................................................................28 开发板键盘实物图.................................................................................................................30 5.达林顿管驱动 ....................................................................................31 达林顿管阵列ULN2003.........................................................................................................31 ULN2003 原理 .......................................................................................................................31 开发板达林顿管实物图.........................................................................................................32 6.继电器 ................................................................................................33 电磁式继电器原理.................................................................................................................33 开发板继电器实验连接图示.................................................................................................34 继电器演示程序.....................................................................................................................34 7.光电耦合器 ........................................................................................35 光电耦合器原理.....................................................................................................................35 Maplead MCU Development Board http://shop63914145.taobao.com 2 光电耦合器演示程序.............................................................................................................35 开发板光耦实验连接图示.....................................................................................................36 8.步进电机 ............................................................................................37 步进电机原理.........................................................................................................................37 开发板步进电机实验连接图示.............................................................................................38 步进电机演示程序.................................................................................................................38 9.51 单片机中断 ...................................................................................41 中断的概念.............................................................................................................................41 51 单片机中断有关的寄存器................................................................................................41 Keil中C语言中断服务函数的形式 .......................................................................................44 10.51 单片机外部中断 .........................................................................45 51 单片机外部中断................................................................................................................45 51 单片机外部中断演示程序................................................................................................45 11.51 单片机定时/计数器 0,1 ..............................................................47 51 单片机定时/计数器 0,1.....................................................................................................47 定时/计数器 0,1 的工作原理.................................................................................................47 定时/计数器的设定及使用....................................................................................................49 定时/计数器 0、1 演示程序..................................................................................................49 12.单片机串口通信 ..............................................................................53 51 单片机串行通信................................................................................................................53 51 单片机串行通信控制寄存器............................................................................................53 串口工作模式解析.................................................................................................................55 串口波特率计算.....................................................................................................................56 串口初始化步骤.....................................................................................................................56 单片机串口通信演示程序.....................................................................................................56 13.1602 液晶显示 .................................................................................59 1602 液晶接口........................................................................................................................59 1602 液晶显示原理................................................................................................................59 1602 液晶指令详解................................................................................................................61 1602 液晶的插接....................................................................................................................68 1602 液晶显示演示程序........................................................................................................69 14.12864 液晶显示 ...............................................................................73 12864 液晶接口......................................................................................................................73 12864 液晶内部控制结构......................................................................................................73 12864 液晶指令详解..............................................................................................................77 12864 液晶在开发板上的安装..............................................................................................81 Maplead MCU Development Board http://shop63914145.taobao.com 3 12864 液晶显示演示程序......................................................................................................83 15.LED点阵 ........................................................................................100 LED点阵原理.......................................................................................................................100 LED点阵的扫描方式...........................................................................................................100 0~9LED数字点阵及其编码.................................................................................................101 LED点阵数字显示演示程序...............................................................................................103 LED点阵实验连接图...........................................................................................................103 16.PS2 接口.........................................................................................105 PS2 接口定义: ...................................................................................................................105 PS2 键盘扫描码 ...................................................................................................................105 PS2 键盘解码演示程序 .......................................................................................................107 开发板PS2 接口实物图 .......................................................................................................108 17.DS1302 实时时钟 ..........................................................................110 DS1302 实时时钟芯片.........................................................................................................110 DS1302 的命令字结构......................................................................................................... 111 DS1302 各寄存器的地址及数据存储结构.........................................................................112 DS1302 的RAM寄存器........................................................................................................114 DS1302 的涓流充电功能.....................................................................................................115 DS1302 的数据输入输出操作.............................................................................................116 开发板实时时钟模块实物图片...........................................................................................118 DS1302 演示程序.................................................................................................................118 18. 红外遥控 .........................................................................................123 红外遥控组成.......................................................................................................................123 红外遥控编码.......................................................................................................................124 51 单片机红外遥控发射模拟..............................................................................................125 红外遥控实验电路连接图示...............................................................................................126 51 单片机红外遥控接收解码设计......................................................................................128 19. AD转换器TLC549...........................................................................135 8 位串口AD转换器TLC549 ................................................................................................135 TLC549 的引脚定义 ............................................................................................................135 TLC549 的操作....................................................................................................................136 开发板AD转换器实验电路连接.........................................................................................137 TLC549 AD转换演示程序...................................................................................................138 20. DA转换器TLC5615 ........................................................................141 10 位串口DA转换器TLC5615 ............................................................................................141 TLC5615 的引脚定义 ..........................................................................................................141 TLC5615 的操作 ..................................................................................................................142 Maplead MCU Development Board http://shop63914145.taobao.com 4 DA转换器实验电路连接.....................................................................................................143 TLC615 DA转换演示程序 ..................................................................................................144 21. SD卡的SPI方式读写.......................................................................146 SD卡及其总线结构..............................................................................................................146 SD卡命令格式......................................................................................................................146 SD卡复位至SPI方式............................................................................................................147 SD卡的SPI方式读写............................................................................................................148 SD卡电路连接实物图..........................................................................................................151 SD卡SPI方式读写演示程序................................................................................................152 22. I2C总线.............................................................................................159 I2C总线简介 .........................................................................................................................159 I2C总线的电气连接 .............................................................................................................159 I2C总线数据传输的启动和停止 .........................................................................................160 I2C总线数据传输格式 .........................................................................................................160 I2C总线器件寻址 .................................................................................................................161 I2C总线器件的读写控制 .....................................................................................................161 I2C总线读写演示程序 .........................................................................................................161 23. AT24C02 芯片的I2C总线读写........................................................165 2K(256×8)AT24C02 E2PEOM ........................................................................................165 AT24C02 的引脚定义 ..........................................................................................................165 AT24C02 的从器件地址 ......................................................................................................166 AT24C02 的字写入 ..............................................................................................................166 AT24C02 的页写入 ..............................................................................................................166 读取AT24C02 当前地址数据 ..............................................................................................167 读取AT24C02 随机地址数据 ..............................................................................................167 连续读取AT24C02 数据 ......................................................................................................168 AT24C02 实验电路连接实物图 ..........................................................................................168 AT24C02 读写演示程序 ......................................................................................................169 24. AT24C04 芯片的I2C总线读写........................................................172 4K(512×8)AT24C04 E2PEOM ........................................................................................172 AT24C04 的引脚定义 ..........................................................................................................172 AT24C04 的从器件寻址 ......................................................................................................173 AT24C04 的读写操作 ..........................................................................................................173 AT24C04 读写演示程序 ......................................................................................................173 25. I2C总线温度传感器LM75A ...........................................................176 LM75A温度传感器..............................................................................................................176 LM75A的引脚定义..............................................................................................................176 LM75A的从器件寻址..........................................................................................................176 Maplead MCU Development Board http://shop63914145.taobao.com 5 LM75A的内部寄存器..........................................................................................................177 LM75A的读写操作..............................................................................................................181 LM75A读取温度值演示程序..............................................................................................184 26. 单总线温度传感器DS18B20 .........................................................190 DS18B20 单总线温度传感器..............................................................................................190 DS18B20 的引脚定义..........................................................................................................190 DS19B20 内部存储器..........................................................................................................190 DS19B20 指令......................................................................................................................191 DS18B20 的读写操作..........................................................................................................193 DS18B20 的温度转换过程..................................................................................................194 DS18B20 在开发板上的安装..............................................................................................194 DS18B20 温度转换演示程序..............................................................................................195 27. 脉宽调制(PWM)输出...............................................................200 PWM原理.............................................................................................................................200 PWM调节LED亮度演示程序 .............................................................................................200 28. 看门狗 .............................................................................................202 看门狗定时器.......................................................................................................................202 看门狗定时器演示程序.......................................................................................................203 29. 51 系列单片机的省电模式 .............................................................205 51 系列单片机的省电模式..................................................................................................205 51 系列单片机的空闲模式..................................................................................................205 51 系列单片机的掉电模式..................................................................................................205 51 系列单片机的电源管理特殊功能寄存器......................................................................205 51 系列单片机的电源管理演示程序..................................................................................206 30. *STC系列单片机内部E2PROM ....................................................209 STC系列单片机的E2PROM ................................................................................................209 ISP/IAP有关的特殊功能寄存器 .........................................................................................209 E2PRM的地址 ......................................................................................................................211 STC90C54RD+的E2PROM读、写以及扇区擦除演示程序 ..............................................211 附录A:USB转串口驱动安装教程 .....................................................215 附录B:STC单片机程序下载方法......................................................222 Maplead MCU Development Board http://shop63914145.taobao.com 1 概述 Maplead 单片机开发/学习板特色 【1】大板、模块化布局。 真正的大板(20cm*12cm),各个模块有序排列,图形化标识,美观、大方、 实用。是您学习、开发的好助手。 【2】板载 USB 转串口模块。 没有串口的笔记本电脑也能使用。芯片采用更加稳定的 CH340T,而非廉价 的 PL2303,用起来更顺手(芯片支持的操作系统有 Windows98/Me/2000/XP/Server2003/Vista/64bit XP/64bit Vista/Windows 7)。 【3】板载工业工程中常用的串口 AD/DA 模块。 本开发板不采用并口通信 AD/DA 芯片,而是采用独立的、最新式的串口通 信 AD/DA 芯片。使您学习一次即可将所学知识在工程实际中得到应用,避免二 次重复学习。AD 模块板载光敏电阻、热敏电阻、可调电阻等多种电压输入方式。 【4】板载光电耦合器。 Maplead MCU Development Board http://shop63914145.taobao.com 2 光电耦合器俗称光耦,是在实际工程应用中常用的隔离器件。 【5】 本开发板/学习板是真正的总线板。 本开发板/学习板采用“总线”的方式将整个板子有机整合在一起。板载 (1)单总线(DS18B20 接口); (2)RS232串口总线; (3)3wire 串口总线(实时时钟/AD/DA); (4)并口总线(1602 液晶、12864 液晶接口); (5)I2C 总线(单页面 AT24C02/双页面 AT24C04/I2C 温度传感器); (6)SPI总线(SD 卡接口); (7)PS2总线接口。 【6】矩阵键盘与独立键盘。 4*4 矩阵键盘、4 独立键盘。 【7】板载点阵模块。 【8】排针一律采用纯铜排针,不生锈,接触性能良好。 【9】电源部分接有 500mA 自恢复保险丝。 板载自恢复保险丝可以有效的保护开发/学习板,即使在短路的情况下也不 会损坏器件。如果您采用电脑 USB 接口供电,本设计能保证您电脑主板的安全。 Maplead MCU Development Board http://shop63914145.taobao.com 3 Maplead 单片机开发/学习板使用须知 ① 单片机 40 引脚全部引出,可以通过这些引脚利用杜邦线自由 连接其它外设。 ② 开发板 USB 接口与 USB 转串口模块。USB 转串口模块的 RxD 与 TxD 端口连接短路子时,单片机串口与 USB 串口相连;RxD 与 TxD 端口去掉短路子时,单片机串口与 USB 串口断开连接。 注意:由于 USB 转串口模块在串口空闲时,RxD 端口输出高 电平,因此,接通 USB 电源后,即使关闭电源按钮的情况下, RxD 端口依然输出微弱的电流,电源指示灯与数码管被微弱 地点亮,但单片机与其他集成电路不工作。拔掉 RxD 短路子 后,开发板彻底断电。 运行矩阵键盘实验或电路板自检程序时,程序下载好了之后, ① ⑥ ⑤ ④ ③ ⑨ ② ⑦ ⑧ ⑩ Maplead MCU Development Board http://shop63914145.taobao.com 4 要先拔掉 RxD 短路子再开机进行实验。 ③ 外接电源插口,插口中心为正极,输入 7~12V 直流电。 ④ 电源指示灯。 ⑤ 电源按钮。该按钮为自锁型开关,按下后接通 USB 电源,弹 起后接通外部直流电源。 ⑥ 电源输出排针。可以引出 6 路 5V 直流电。 ⑦ SD 卡模块的 3.3V 电压输出端,该端口可以输出+3.3V 直流电 压,负极可以连接⑥的 GND 端口。 ⑧ ISP 插口。Atmel 公司 51 系列单片机程序下载接口,通过该接 口可以用编程器对 AT89 系列单片机进行编程操作。该端口为 标准 Atmel 接口定义。 ⑨ RS232 串行接口。该接口可以直接与电脑 RS232 接口进行连 接并与电脑进行串行通信。 ⑩ 继电器接线端子。3 个端口,最上面一个端子与中间端子在平 时是相互接通的,在继电器吸合后断开;最下面一个端子与中 间端子在平时是断开的,在继电器吸合后接通。 注意:尽管继电器可以连接 220V 交流电,但不推荐大家采用 220V 交流电进行实验,可以使用低电压的电源代替 220V 交 流电进行演示。请时刻注意用电安全! Maplead MCU Development Board http://shop63914145.taobao.com 5 开发板各模块简介 Maplead MCU Development Board http://shop63914145.taobao.com 6 Maplead MCU Development Board http://shop63914145.taobao.com 7 Maplead MCU Development Board http://shop63914145.taobao.com 8 Maplead MCU Development Board http://shop63914145.taobao.com 9 Maplead MCU Development Board http://shop63914145.taobao.com 10 Maplead MCU Development Board http://shop63914145.taobao.com 11 板载资源 【01】8 个 LED 发光二极管。白发红、白发黄两种颜色 LED,经典流水灯 等实验。 【02】8 位共阴数码管。74hc573 与 74HC138 总线扩展。1 位数码管静态显 示、8 位数码管动态显示。 【03】4×4 矩阵键盘。配有线反转法输入程序样例。 【04】4 个独立按键。独立按键扫描、外部中断输入、计数器输入。 【05】达林顿管阵列模拟电路驱动。 【06】电磁继电器驱动电路。 【07】步进电机驱动电路。 【08】直流电机驱动电路。 【09】光电耦合器驱动电路。 【10】无源蜂鸣器驱动电路。警报音、单片机音乐演奏。 【11】USB 转串口电路。方便无串口的笔记本电脑进行单片机开发实验。 【12】单片机 RS232 串口通信接口。 【13】1602 液晶显示接口。 【14】12864 液晶显示接口。 【15】8×8LED 点阵显示接口。 【16】红外遥控收发。 【17】PS2 键盘/鼠标接口。 【18】3 线制串行总线实时时钟。带涓流充电功能的实时时钟。 【19】3 线制串行总线 AD 转换器。拨码开关选择精密可调电阻、热敏电阻、 光敏电阻、外部模拟输入。 【20】3 线制串行总线 DA 转换器。电压控制 LED 亮度、模拟输出。 【21】SPI 总线对 SD 卡的读写操作。 Maplead MCU Development Board http://shop63914145.taobao.com 12 【22】I2C 总线操作 AT24C02。拨码开关自由变换器件地址。 【23】I2C 总线操作 AT24C04。拨码开关自由变换器件地址。 【24】I2C 总线操作温度传感器。拨码开关自由变换器件地址。 【25】DS18B20 单总线温度传感器。 【26】ISP 接口。兼容 Atmel 原厂接口定义,可用编程器进行 AT89 系列程 序下载。 【27】USB 电源输入或 7~12V 电源输入。 【28】500mA 自恢复保险丝。保护电路安全;USB 供电时保护电脑主板安 全。 【29】红外遥控收发。 【30】单片机所有引脚全部引出。全铜排针,不生锈,接触性能好。 Maplead MCU Development Board http://shop63914145.taobao.com 13 1.流水灯 图 1-1 流水灯电路连接原理图 流水灯原理 51 单片机所有 I/O 引脚通过场效应管输出低电平,通过上拉电阻输出高电平 (P0 口需要外加上拉电阻),因此其低电平的驱动能力较强,高电平的驱动能力非 常弱。 流水灯的工作原理很简单:所有的 LED 发光二极管共阳连接(正极接到一 起),依靠单片机引脚输出低电平(接通负极)来点亮各个发光二极管。 开发板流水灯实物图 Maplead MCU Development Board http://shop63914145.taobao.com 14 图 1-2 开发板流水灯 流水灯演示程序 例程 1-1 流水灯(对应的电路为图 1-1) /****************************************************************************** * 流水灯 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include //引用“reg52.h”头文件,此文件中包含对单片机寄存器等的定义 void delay(void); //delay()函数预定义;ANSI C 规定所有函数须在 main 函数前进行预定义 void main(void) { unsigned char a,i; while(1) //超级循环 { a=0x01; //给 a 赋初值 1,既 a 的最低位为 1 for(i=0;i<8;i++) { P1=~a; //将 a 值取反后赋给 P1 口,因为 LED 为低电平点亮 a<<=1; //本表达式同 a=a<<1; 每次都将 a 变量左移 1 位,共移 8 次 delay(); //给一定的延时,否则肉眼无法感知流水灯的变化 } } } void delay(void) { unsigned int i,j; for(i=0;i<500;i++) //空循环 65000*10 次,进行延时; for(j=0;j<250;j++); //调节 j 值,改变流水灯闪烁速度,j 值越大,速度越慢 } Maplead MCU Development Board http://shop63914145.taobao.com 15 2.数码管 数码管原理 图 2-1 数码管电路原理图 数码管每个数字称为“位”;单个数字内每个 LED 灯称为“段”。 共阴数码管所有段的阴极共用一引脚;共阳数码管所有段的阳极共用一引 脚。 如图 2-1 所示的数码管,分别为 1 个数字 8 个段,则称为“8 段 1 位数码管”。 我们开发板上安装的数码管为 8 段,4 位 1 组,共两组,所以称为 8 段 8 位数码 管。 数码管的显示原理为:如果我们要用 8 段数码管显示一个“1”字,则“b”、“c” 两段被点亮;如果我们要显示一个“9”字,则“a”、“b”、“c”、“d”、“f”、“g”六段 被点亮;如果需要显示小数点,则“dp”段被点亮。 8 段数码管编码 a、b、c、d、e、f、g 这 7 段与 dp 这个显示小数点的段加起来刚好是 8 段, 正好可以用 8 个位,也就是 8 位单片机的一个机器字来表示。我们可以将十六 进制的 0~F 这 16 个数字进行编码存储于某一变量中,方便使用。 表 2-1 数字段码在 8 位机器字中的存放 K 1 f2 g3 e4 d5 K 6 c8 DP7 b9 a10 a b c d e f g dp GND 共阴数码管 A 1 f2 g3 e4 d5 A 6 c8 DP7 b9 a10 b c d e f g dp a VCC 共阳数码管 a b c d e f g dp a b c d e f g dp Maplead MCU Development Board http://shop63914145.taobao.com 16 MSB LSB 字节中每个位 D7 D6 D5 D4 D3 D2 D1 D0 对应的段 dp g f e d c b a 表 2-2 8 段共阴数码管编码表(共阳取反) 显示数字 0 1 2 3 4 二进制编码 0011 1111 0000 0110 0101 1011 0100 1111 0110 0110 十六进制编码 0x3F 0x06 0x5B 0x4F 0x66 显示数字 5 6 7 8 9 二进制编码 0110 1101 0111 1101 0000 0111 0111 1111 0110 1111 十六进制编码 0x6D 0x7D 0x07 0x7F 0x6F 显示数字 A B C D E 二进制编码 0111 0111 0111 1100 0011 1001 0101 1110 0111 1001 十六进制编码 0x77 0x7C 0x39 0x5E 0x79 显示数字 F 无显示 使用小数点显示的数字 二进制编码 0111 0001 0000 0000 最高有效位取 1 十六进制编码 0x71 0x00 / 数码管显示方式 LED 显示器工作方式有两种:静态显示方式和动态显示方式。 静态显示方式: 静态显示的特点是每个数码管的段选必须接 8 条数据线来保持显示的字形 码。当送入一次字形码后,显示字形可一直保持,直到送入新字形码为止。这种 方法的优点是占用 CPU 时间少,显示便于监测和控制。缺点是占用较多的硬件 电路端口,成本较高。 Maplead MCU Development Board http://shop63914145.taobao.com 17 图 2-2 数码管的静态显示 动态显示方式: 动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪 一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各 位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使 人的感觉好像各位数码管同时都在显示。动态显示的亮度比静态显示要差一些, 所以在选择限流电阻时应略小于静态显示电路中的。 图 2-3 数码管的动态显示 K 1 f2 g3 e4 d5 K 6 c8 DP7 b9 a10 K 1 f2 g3 e4 d5 K 6 c8 DP7 b9 a10 接同一总线 12 分时选通,每一瞬间 只点亮一个数码管 K 1 f2 g3 e4 d5 K 6 c8 DP7 b9 a10 K 1 f2 g3 e4 d5 K 6 c8 DP7 b9 a10 GND 接总线1 接总线2 同一时刻,所有数码管同时被点亮 Maplead MCU Development Board http://shop63914145.taobao.com 18 开发板数码管实物图 图 2-4 开发板数码管 数码管演示程序 图 2-5 例程电路图 例程 2-1 数码管静态显示 /****************************************************************************** * 数码管静态显示 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77, 0x7C,0x39,0x5E,0x79,0x71}//数码管段编码 void delay(void); //函数声明 void main(void) { Maplead MCU Development Board http://shop63914145.taobao.com 19 unsigned char i; while(1) //超循环 { for(i=0; i<16; i++) { P0=LED_Seg [i]; //将 0~F 的编码送到 P0 口,在数码管上显示 0~F delay(); //延时,以便观察数码管的变化 } } } void delay(void) { unsigned int i,j; for(i=0;i<500;i++) //空循环 65000*10 次,进行延时; for(j=0;j<250;j++); //调节 j 值,改变流水灯闪烁速度,j 值越大,速度越慢 } 例程 2-2 数码管动态显示 /****************************************************************************** * 数码管动态显示 ******************************************************************************/ #include unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77, 0x7C,0x39,0x5E,0x79,0x71}//数码管段码 unsigned char code LED_Bit[]={0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00} //数码管位码 void delay(void); void main(void) { unsigned char i; while(1) //超循环 { for(i=0; i<8; i++) //8 个位分别显示 0~7 { P2= LED_Bit[i]; //将每个数字的位码送到 P2 口,在每个位上显示特定的数字 P0= LED_Seg[i]; //将 0~7 的段码送到 P0 口,在数码管上显示 0~7 delay(); //延长每个位显示的时间,增强数码管亮度 P0=0x00; //关闭前一个位的编码输入,防止下一位重影 } } void delay(void) //延时不能过长,否则数码管显示会明显地闪烁 { Maplead MCU Development Board http://shop63914145.taobao.com 20 unsigned int i,j; for(i=0;i<1000;i++); } Maplead MCU Development Board http://shop63914145.taobao.com 21 3.总线扩展技术 总线扩展 在实际的设计使用过程中,单片机片上的 I/O 口无论从数量上还是驱动能力 上往往是不够的,这时候就需要对单片机的 I/O 口进行扩展,以满足实际需要的 I/O 数量或驱动能力。 对单片机的 I/O 口进行扩展大都采用专门的集成芯片,如并行接口芯片 8255、74 系列的总线驱动芯片等。 本开发板数码管显示单元所使用的总线扩展芯片为 74HC138 和 74HC573 两 款集成芯片。 74HC138 图 3-1 74HC138 引脚图 又称为 3-8 译码器,其真值表为: 表 3-1 74HC138 真值表 H-高电平,1; L-低电平,0; X-任意电平值。 A01 A12 A23 E14 E25 E36 Y77 GND8 Y6 9 Y5 10 Y4 11 Y3 12Y2 13Y1 14Y0 15VCC 16 74HC138 Maplead MCU Development Board http://shop63914145.taobao.com 22 由上表可见: , ,E3 为三个使能开关。只有当 端与 端同时为低, 而 E3 端为高时,才能在 8 个输出端输出某个低电平,否则,输出全为高电平。 , ,E3 都使能时,随着输入 A1、A2、A3 端的值不同,Y0~Y7 输出 不同的值,但每次只能输出一个低电平。 因此,只使用了 3 个引脚就能够控制 8 个引脚,从而扩展了单片机端口的数 量。 74HC573 图 3-2 74HC573 引脚图 其真值表为: 表 3-2 74HC573 真值表 X-任意电平值 Z-高阻态(相当于断开连接) OE 端口为输出使能,低电平有效,控制 74HC573 芯片的 D 总线(输入) OE1 D02 D13 D24 D35 D46 D57 D68 D79 GND10 LE 11Q7 12Q6 13Q5 14Q4 15Q3 16Q2 17Q1 18Q0 19VCC 20 74HC573 Maplead MCU Development Board http://shop63914145.taobao.com 23 和 Q 总线能否联通,当 OE 端使能且 LE 为高时,Q 总线的值=D 总线的值; LE 为锁存使能端口,低电平有效,当其使能时,74HC573 的 Q 总线被锁存 (Q 总线保持上个状态不变,不再随 D 总线变化而变化)。 将多个 74HC573 的 D 总线连接至单片机的同一端口上,通过控制不同 74HC573 的 LE 端口,在同一时刻只将某个数值输出到某个特定的 74HC573 上, 从而实现了单片机端口的扩展。 开发板 74HC138 与 74HC573 实物图 图 3-3 开发板 74HC573 与 74HC138 Maplead MCU Development Board http://shop63914145.taobao.com 24 4.键盘 独立键盘 图 4-1 独立键盘电路原理图 独立键盘原理: 如图 4-1 所示,独立键盘每个按键的一脚接地,另一脚接单片机相应的 I/O 口,每个单片机 I/O 口需设定为输入模式(向该口写“1”)。单片机连接独立按键 的 I/O 口循环检测该口状态,如果该口检测为低电平,则证明连接该口的按键有 可能被按下,然后单片机执行相应动作。 键盘去“抖动”: 键盘的按键在闭合和断开的瞬间存在电压的不稳定状态,称为按键的“抖 动”。按键的这种“抖动”现象容易引起误操作,如,按下一次按键有可能使单片 机检测到按键被多次按下,所以必须采取相应的措施消除这种输入过程中的“抖 动”现象。 在工程设计中,人们往往采用软件延时 5~10ms“跳过抖动”的方法来消除按 键的“抖动”现象。采用软件消抖技术既简单又不需要额外的硬件电路,因此在实 际中得到了广泛的应用。 图 4-2 键盘的“抖动”现象 理想波形 实际波形 “抖动”现象 延时 5~10ms“跳过” K1 K2 K3 K4 GND P32 P33 P34 P35 独立键盘 Maplead MCU Development Board http://shop63914145.taobao.com 25 独立键盘演示程序 例程 4-1 独立键盘(对应的电路为图 4-1) /****************************************************************************** * 独立键盘 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ sbit K1=P3^2; sbit K2=P3^3; sbit K3=P3^4; sbit K4=P3^5; /***************************************************************************** * 键盘扫描函数 *****************************************************************************/ unsigned char Key_Scan(void) { P3=0xFF; //P3 口设置为输入状态 if(!K1) //如果此端口不为 1,证明有键按下 { delay(); //延时去抖 if(!K1) //如果延时过后依然是低电平证明不是误操作 while(!K1); //等待释放按键 return 1; //返回键值 } if(!K2) { delay(); if(!K2) while(!K2); return 2; } if(!K3) { delay(); if(!K3) while(!K3); return 3; } if(!K4) { delay(); if(!K4) Maplead MCU Development Board http://shop63914145.taobao.com 26 while(!K4); return 4; } return 0xFF; //无键按下返回 0x00 } /************************************************************************** * 延时函数 **************************************************************************/ void delay() //延时 10ms (12MHz 晶体) { unsigned int i; for(i=0;i<2000;i++); } 矩阵键盘 图 4-3 矩阵键盘电路原理图 矩阵键盘通过 m 条行线与 n 条列线交叉形成 m×n 个交点,这些交点并不直 K1 K2 K3 K4 K7 K8 K9 K10 K11 K12 K13 K14 K16 P30 P31 P32 P33 P34 P35 P36 P37 K5 K6 K15 4*4 矩阵键盘 Maplead MCU Development Board http://shop63914145.taobao.com 27 接连通,而是通过 m×n 个按键连接。矩阵键盘的好处是按键容量大,可以有效 节省单片机 I/O 口。 单片机对矩阵键盘按键的扫描识别比独立按键复杂。常用的扫描识别方法是 “线反转法”。其扫描原理是: A. 先将行线(P3.0~P3.3)置低电平,将列线(P3.4~P3.7)置高电平,即 P3=11110000。 B. 循环检测 P3 口,如果 P3 口的值不等于且消抖后也不等于 11110000,证 明有键被按下(高电平的端口会被低电平的端口拉为低电平)。 C. 将 P3 口的值保存至(usigned char)变量 Key_Uper。 D. 将行线(P3.0~P3.3)置高电平,将列线(P3.4~P3.7)置低电平,即 P3=00001111 (行列电平进行了反转) 。 E. 将 P3 口的值保存至(usigned char)变量 Key_Lower。 F. 将 Key_Uper 和 Key_lower 两变量相加,将结果保存至(usigned char)变量 Key_Val 中。 G. 等待释放按键。 H. 查键值表,找到 Key_Val 所对应的键值,确定哪个键被按下了。 I. 做相应的处理动作。 例 4-1:K3 键按下后,扫描程序所做的处理 A. 对应图 4-3,先将 P3 口赋值为 11110000,则 P3.4~P3.7 为输入口。 B. 当 K3 键被按下的时候,P3 口的值变为 10110000,不等于且消抖后也不 等于 11110000。 C. 单片机将 P3 口的值 10110000 保存在(usigned char)变量 Key_Uper 中。 D. 行列电平反转,即 P3=00001111。 E. 此时由于 K3 键依然闭合,P3 口的值变为 00001110,将此值存于变量 Key_Lower 中。 Maplead MCU Development Board http://shop63914145.taobao.com 28 F. Key_Uper 和 Key_lower 两变量相加,得到结果 10111110(转换为十六 进制为 0xBE),将此结果存于变量 Key_Val 中。 G. 等待释放按键。 H. 查键值表,得到 0xBE 键值,确定 K3 键被按下。 I. 做相应的处理动作。 表 4-1 矩阵键盘的键值编码 键 K1 K2 K3 K4 K5 K6 K7 K8 编码 EE DE BE 7E ED DD BD 7D 键 K9 K10 K11 K12 K13 K14 K15 K16 编码 EB DB BB 7B E7 D7 B7 77 矩阵键盘演示程序 例程 4-2 矩阵键盘 /****************************************************************************** * 键盘扫描函数 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ unsigned char Key_Scan(void) { unsigned char Key_Uper, Key_Lower, Key_Val;//列扫描值,行扫描值,键盘扫描最终结 果 P3=0xF0; //列置为输入状态 if(P3!=0xF0) { delay(); //延时消抖 if(P3!=0xF0) //确认键真的被按下 { Key_Uper=P3; //保存列扫描结果 P3=0x0F; //行置为输入状态 Key_Lower=P3; //保存行扫描结果 Key_Val=Key_Lower+Key_Uper; //保存行列扫描结果 Maplead MCU Development Board http://shop63914145.taobao.com 29 while(P3!=0x0F); //等待释放按键 switch(Key_Val) //查表,返回键值 { case 0xEE: return 0; break; case 0xDE: return 1; break; case 0xBE: return 2; break; case 0x7E: return 3; break; case 0xED: return 4; break; case 0xDD: return 5; break; case 0xBD: return 6; break; case 0x7D: return 7; break; case 0xEB: return 8; break; case 0xDB: return 9; break; case 0xBB: return 10; break; case 0x7B: return 11; break; case 0xE7: return 12; break; case 0xD7: return 13; break; case 0xB7: return 14; break; case 0x77: return 15; break; } } } return 255; //返回 0xFF,表示没有键被按下 } Maplead MCU Development Board http://shop63914145.taobao.com 30 开发板键盘实物图 图 4-3 开发板矩阵键盘(4×4 黑色)与独立键盘(竖排红色) Maplead MCU Development Board http://shop63914145.taobao.com 31 5.达林顿管驱动 达林顿管阵列 ULN2003 ULN2003 是大电流驱动阵列,多用于单片机、智能仪表、PLC、数字量输 出卡等控制电路中。可直接驱动继电器等负载。输入 5VTTL 电平,输出可达 500mA/50V。 图 5-1 达林顿管阵列原理图 ULN2003 原理 如图 5-1 所示,1~7 端口为输入端口;10~16 端口为输出端口。 当输入端口输入高电平时,输出端口输出大功率低电平。每个达林顿管内部 集成有一个继流二极管(使用时须将第“9”脚接 Vcc 端),目的是在驱动感性电路 时为电路提供一个“继流”的通路(相当于将电器反向短路,消耗电磁感应产生的 反向电流,以保护达林顿管不被反向电动势击穿)。 本开发板中所用到的继电器、无源蜂鸣器、步进电机、直流电机、光耦都是 通过达林顿管阵列 ULN2003 驱动的。 Maplead MCU Development Board http://shop63914145.taobao.com 32 开发板达林顿管实物图 图 5-2 开发板达林顿管阵列芯片 Maplead MCU Development Board http://shop63914145.taobao.com 33 6.继电器 电磁式继电器原理 继电器是一种电子控制器件,它用较小的电流(电压)去控制较大电流的一种 “自动开关”。在电路中起着自动调节、安全保护、转换电路等作用。 电磁式继电器是利用电磁铁制成的。本开发板中所使用的继电器分为“输 入”、“常开”和“常闭”三个输入端。 如图 5-1 所示,端口“1”为“常开”端;端口“2”为“输入”端;端口“3”为“常闭” 端。输入端输入电源。 当继电器不工作时,继电器开关被弹簧拉至“常开端”,电源可以通过“常开” 端输出。 当继电器工作时,继电器的开关被电磁铁吸引拉至“常闭”端,“常开”端关闭, “常闭”端与“输入”端接通,电源通过“常闭”端输出。 图 5-1 继电器原理图 Maplead MCU Development Board http://shop63914145.taobao.com 34 开发板继电器实验连接图示 图 5-1 实验前用杜邦线将 P1.1 与达林顿管输入的“R”相连 继电器演示程序 例程 6-1 继电器驱动 /****************************************************************************** * 继电器驱动程序 * (1)单片机 P1.1 口接开发板上达林顿阵列的“R”输入端。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ sbit R=P1^1; void Relay(bit a) //当传递的参数为“1”时继电器工作,为“0”时停止工作 { R=a; } Maplead MCU Development Board http://shop63914145.taobao.com 35 7.光电耦合器 光电耦合器原理 “光电耦合器”又称为“光耦”。 它是以光为媒介来传输电信号的器件,通常 把发光器(红外线发光二极管 LED)与受光器(光敏半导体管)封装在同一管 壳内。当输入端加电信号时发光器发出光线,受光器接受光线之后就产生光电流, 从输出端流出,从而实现了“电-光-电”转换。以光为媒介把输入端信号耦合到输 出端的光电耦合器,由于它具有体积小、寿命长、无触点,抗干扰能力强,输出 和输入之间绝缘,单向传输信号等优点,在数字电路上获得广泛的应用。 在电路设计中,光耦常被用作电路与电路之间的隔离器件,以期达到隔离干 扰的目的。例如:数字电路与模拟电路之间的隔离。 如图 7-1 所示,当光耦的端口 2 接低电平后,外电流就可以从端口 4 流至端 口 3。 图 7-1 光耦电路 光电耦合器演示程序 例程 7-1 光耦驱动 /****************************************************************************** * 光耦驱动程序 * (1)单片机 P1.4 口接开发板上达林顿阵列的“P”输入端。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ sbit P=P1^4; void PhCoupler (bit a) //当传递的参数为“1”时光耦工作,为“0”时停止工作 Maplead MCU Development Board http://shop63914145.taobao.com 36 { P =a; } 开发板光耦实验连接图示 图 7-2 实验前将 P1.4 端口与达林顿管输入的“P”相连 Maplead MCU Development Board http://shop63914145.taobao.com 37 8.步进电机 步进电机原理 步进电机是将电脉冲信号转变为角位移或线位移的机械。在非超载的情况 下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变 化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向 转动一个固定的角度,称为“步距角”,它的旋转是以固定的角度一步一步运行的。 可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通 过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。 本开发板步进电机原理图如图 8-1 所示。 5 线制步进电机内部有 4 只电磁铁,当接通某个电磁铁后,中间的转子“E” 便在磁力的作用下转向此电磁铁,如果电磁铁接通的顺序为“A-B-C-D”则,转子 “E”便在磁力的作用下转动一周。其转动的角度为 45 度。 如果控制电磁铁导通的顺序为“A-AB-B-BC-C-CD-D”,则原来的步进角度变 为 22.5 度。 图 8-1 步进电机原理图 注意:本开发板配套的步进电机为减速步进电机,其步进角度为原始的 1/64 A B C D E Maplead MCU Development Board http://shop63914145.taobao.com 38 开发板步进电机实验连接图示 图 8-2 步进电机实验电路连接 (1) P1.0 连接达林顿输入端的“A”; (2) P1.1 连接达林顿输入端的“B”; (3) P1.2 连接达林顿输入端的“C”; (4) P1.3 连接达林顿输入端的“D”; 图 8-3 步进电机排线与步进电机专用插座连接 步进电机演示程序 例程 8-1 步进电机驱动 /****************************************************************************** * (1)晶振 12MHz 调试通过。 * (2)采用杜邦线将开发板的 P1.0~P1.3 输出排针分别与达林顿驱动输入的“A,B,C,D”* 排针相连。 Maplead MCU Development Board http://shop63914145.taobao.com 39 * (3)按下 F1 按键,步进电机打开;再按一次 F1 键,步进电机关闭。如此循环往复。 * (4)电机启动正转,按下 F2 键后电机反转,再次按下 F2 后,电机正转,如此循环往复。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. *****************************************************************************/ #include sbit F1=P3^2; //F1 键控制电机的开关 sbit F2=P3^3; //F2 键控制电机的正反转 unsigned char Stpmotor_F[]={0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09}; //正转(forward) unsigned char Stpmotor_B[]={0x09,0x08,0x0C,0x04,0x06,0x02,0x03,0x01}; //反转(backward) bit F_B_Status =1; //正反转标志,0:反转;1:正转 bit ON_OFF =1; //步进电机开关标志位,0:关; 1:开 void delay(void); void main(void) { unsigned char i; while(1) { if(ON_OFF) { if(F_B_Status) //正转 { for(i=0;i<8;i++) { P1=Stpmotor_F[i]; delay(); } } else //反转 { for(i=0;i<8;i++) { P1=Stpmotor_B[i]; delay(); } } } else P1=0x00; //如果关闭,则关闭达林顿管 Maplead MCU Development Board http://shop63914145.taobao.com 40 if(!F1) { delay(); if(!F1) ON_OFF=~ON_OFF; while(!F1); } if((!F2) && (ON_OFF==1)) { delay(); if(!F2) F_B_Status=~F_B_Status; while(!F2); } } } /***************************************************************************** * 延时函数 ******************************************************************************/ void delay(void) //可以通过调节 i 值来调节电机速度,可以将程序扩展增加速度控制功能。 { unsigned int i; for(i=0;i<300;i++); //i 值不能调太小,否则电机到达最高工作频率上限后停止转动。 } Maplead MCU Development Board http://shop63914145.taobao.com 41 9.51 单片机中断 中断的概念 图 9-1 中断示意图 (1) 中断发生:当系统正在处理 A 事件的时候,突然发生了比较紧急 的 B 事件,要求系统迅速做出处理。 (2) 中断响应和处理:系统暂停当前 A 事件的处理(保存状态),转去 处理 B 事件。 (3) 中断返回:事件 B 处理完毕,系统返回被事件 B 打断的地方继续 处理 A 事件。 以上 3 个完整的过程成为中断。 51 单片机中断有关的寄存器 (1)IE(Interrupt Enable Register)寄存器 表 9-1 IE 寄存器 位 7 6 5 4 3 2 1 0 IE (A8H) 功能 EA - ET2 ES ET1 EX1 ET0 EX0 9 EA(Enable All Interrups):总中断使能位。0:关闭;1:使能。 9 ET2(Enable Timer/Counter 2):T/C2 中断使能位。0:关闭;1:使能。 9 ES(Enable Serial Port):串行口中断使能位。0:关闭;1:使能。 9 ET1(Enable Timer/Counter 1):T/C1 中断使能位。0:关闭;1:使能。 9 EX1(Enable External Interrupt 1):INT1 中断使能位。0:关闭;1:使 主程序 断点 中断处理程序 转移 返回 主程序 Maplead MCU Development Board http://shop63914145.taobao.com 42 能。 9 ET0(Enable Timer/Counter 0):T/C0 中断使能位。0:关闭;1:使能。 9 EX0(Enable External Interrupt 0):INT0 中断使能位。0:关闭;1:使 能。 (2)IP(Interrupt Priority Register)寄存器 80C51 单片机有 2 个中断优先级,可实现中断 2 级嵌套。 80C52 单片机有 4 个中断优先级,可实现中断 4 级嵌套。 表 9-2 IP & IPH 寄存器 位 7 6 5 4 3 2 1 0 IP (B8H) 功能 - PT2 PS PT1 PX1 PT0 PX0 位 7 6 5 4 3 2 1 0 IPH (B7H) 功能 - PT2H PSH PT1H PX1H PT0H PX0H 9 PT2(Priority of Timer/Counter 2):定时/计数器 2 中断优先级设定位。 0:低优先级;1:高优先级。 9 PS(Priority of Serial Port):串行口中断优先级设定位。0:低优先级; 1:高优先级。 9 PT1(Priority of Timer/Counter 1):定时/计数器 1 中断优先级设定位。 0:低优先级;1:高优先级。 9 PX1(Priority of External Interrupt 1):外部中断 1 优先级设定位。0: 低优先级;1:高优先级。 9 PT0(Priority of Timer/Counter 0):定时/计数器 0 中断优先级设定位。 0:低优先级;1:高优先级。 9 PX0(Priority of External Interrupt 0):外部中断 0 优先级设定位。0: 低优先级;1:高优先级。 9 PT2H、PSH、PT1H、PX1H、PT0H、PX0H 等几个位与其相应的低位功 能相同,由两个位搭配组合,从而可以为单片机设定 4 级中断优先级。 Maplead MCU Development Board http://shop63914145.taobao.com 43 其数值越高,优先级越高。例如:PS=1; PSH=1; 则串口中断优先级=4, 为最高优先级。 (3)TCON(Timer/Counter0,1 Control) 表 9-3 TCON 位 7 6 5 4 3 2 1 0 TCON (88H) 功能 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 9 TF1(T/C1 Overflow):定时/计数器 1 溢出中断请求标志位。中断发生 时该位置 1,中断响应后该位由单片机自动清零。 9 TR1(T/C1 Run):定时/计数器 1 运行标志位。0:停止运行;1:开始 运行。 9 TF0(T/C0 Overflow):定时/计数器 0 溢出中断请求标志位。中断发生 时该位置 1,中断响应后该位由单片机自动清零。 9 TR0(T/C0 Run):定时/计数器 0 运行标志位。0:停止运行;1:开始 运行。 9 IE1(Interrupt 1 Enable):外部中断 1 使能。0:禁止;1:使能。 9 IT1(Interrupt 1 Type):外部中断触发方式选择。IT1=0 时为低电平触发 方式;IT1=1 时,为下降沿触发方式。 9 IE0(Interrupt 0 Enable):外部中断 0 使能。0:禁止;1:使能。 9 IT0(Interrupt 0 Type):外部中断触发方式选择。IT0=0 时为低电平触发 方式;IT0=1 时,为下降沿触发方式。 (4)SCON(Serial Port Control) 表 9-4 SCON 位 7 6 5 4 3 2 1 0 SCON (98H) 功能 - - - - - - TI RI 9 TI(Transmit Interrupt):发送完毕中断标志位。当串口发送完 1 字节数 据后该位置位。此位必须由软件清除。 Maplead MCU Development Board http://shop63914145.taobao.com 44 9 RI(Receive Interrupt):接收完毕中断标志位。当串口接收完 1 字节数 据后该位置位。此位必须由软件清除。 Keil 中 C 语言中断服务函数的形式 Keil 中定义中断服务函数的形式为: void fun(void) interrupt n [using n] { 中断处理程序…… } 9 中断服务函数的名字(fun)可以自由指定,但其类型必须是 void 类型。 9 所有中断服务函数都没有形参,或者说形参为 void。 9 关键字 interrupt 后面跟的是中断号,分别表示各个中断的入口地址 (8n+3)。 9 using 关键字可以使用也可以不使用,其作用是做工作寄存器组的转换 以减少压栈操作。n 的数值即是工作寄存器组的编号,因为 51 单片机工 作寄存器组共有 4 组所以 n 的取值范围为 0~3。 Maplead MCU Development Board http://shop63914145.taobao.com 45 10.51 单片机外部中断 51 单片机外部中断 STC89C51RC 单片机包括 2 个外部中断源:INT0(与 P3.2 端口复用)和 INT1 (与 P3.3 端口复用)。当有外部事件变化时(低电平或下降沿)触发相应的中断。 表 10-1 TCON 寄存器中外部中断的各功能位 位 7 6 5 4 3 2 1 0 TCON (88H) 功能 - - - - IE1 IT1 IE0 IT0 9 IE1(Interrupt 1 Enable):外部中断 1 使能。0:禁止;1:使能。 9 IT1(Interrupt 1 Type):外部中断触发方式选择。IT1=0 时为低电平触发 方式;IT1=1 时,为下降沿触发方式。 9 IE0(Interrupt 0 Enable):外部中断 0 使能。0:禁止;1:使能。 9 IT0(Interrupt 0 Type):外部中断触发方式选择。IT0=0 时为低电平触发 方式;IT0=1 时,为下降沿触发方式。 外部中断 0,1 有两种触发方式: (1)低电平触发方式。当 IT0/IT1=0 时,外部中断为低电平触发方式。 (2)下降沿触发方式。当 IT0/IT1=1 时,外部中断为下降沿触发方式。 设定外部中断的一般步骤为: (1)设定中断触发方式(IT0/IT1)。 (2)使能外部中断(IE0/IE1=1)。 (3)使能 CPU 总中断(EA=1)。 51 单片机外部中断演示程序 例程 10-1 外部中断 0 处理函数 /****************************************************************************** * 外部中断 0 * (1)由于开发板上独立按键的 K1 连接至 P3.2 口,即 INT0 口,所以当 K1 按下的 * 时候便触发 INT0 中断,流水灯的第一个发光二极管点亮。当松开 K1 时,程 Maplead MCU Development Board http://shop63914145.taobao.com 46 * 序返回主程序中,将发光二极管关闭。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. *****************************************************************************/ #include void main(void) { IT0 = 1; //外部中断 0 采用下降沿触发方式 EX0 = 1; //开外部中断 0 EA = 1; //开总中断 while(1) { P1=0XFF; //关闭所有发光二极管 } } /****************************************************** * 外部中断 0 处理函数 ******************************************************/ void Int0_ISR()interrupt 0 using 1 //using 1 是指使用第 1 组工作寄存器,也可以不指定 { P1=0XFE; //点亮第一个发光二极管 } Maplead MCU Development Board http://shop63914145.taobao.com 47 11.51 单片机定时/计数器 0,1 51 单片机定时/计数器 0,1 在实际的测控系统中,常常需要定时控制或者对外部事件进行计数,定时/ 计数器可以完成这样的功能。 51 单片机内部一般存在 2~3 个定时/计数器,每个定时/计数器都是 16 位的 可编程定时/计数器。可编程定时/计数器的工作方式、定时时长、量程、启动方 式等都是由相应指令控制的。 定时/计数器 0,1 的工作原理 51 单片机的定时/计数器实质上是加 1 计数器。 由单片机外部时钟信号进行的加 1 操作称为计数器。计数器的作用是对外部 脉冲的个数进行计数,外部脉冲的下降沿触发计数器进行计数。应当注意的是, 外部脉冲的持续时间应该要大于一个机器周期的时长,否则计数器将不能精确记 录外部脉冲的个数。 由于 51 单片机的外部晶振频率精确固定,其内部机器周期也是精确固定的, 由 51 单片机内部时钟进行的加 1 操作称为定时器。定时器的作用是对某个操作 过程进行定时或者计时。一般说来,定时器的加 1 频率等于单片机一个机器周期 的频率,即在每个机器周期单片机定时器自动加 1。 51 单片机由 2 个特殊功能寄存器对定时/计数器 0,1 分别进行控制管理,分 别为 TMOD 和 TCON。 (1)定时/计数器模式选择寄存器 TMOD 表 11-1 定时/计数器模式选择寄存器 TMOD 位 7 6 5 4 3 2 1 0 TMOD (89H) 功能 GATE C/T1 M1 M0 GATE C/T0 M1 M0 定时/计数器 1 定时/计数器 0 9 GATE(位 7):T1 的门控位。当 GATE=0 时,只要 TR1=1 定时/计数器便 启动。当 GATE=1 时,除 TR1=1 外,还要 INT1 引脚为高电平才能启动 定时/计数器 1。 Maplead MCU Development Board http://shop63914145.taobao.com 48 9 C/T1(Counter/Timer1):定时/计数器 1 功能选择位。C/T1=0 时,为定时 器;C/T1=1 时,为计数器。 9 M1 和 M0(Mode)(位 5 和位 4)():定时/计数器 1 方式选择位(详细见 表 11-2 介绍)。 9 GATE(位 3):T0 的门控位。当 GATE=0 时,只要 TR0=1 定时/计数器便 启动。当 GATE=1 时,除 TR0=1 外,还要 INT0 引脚为高电平才能启动 定时/计数器 0。 9 C/T0(Counter/Timer0):定时/计数器 1 功能选择位。C/T0=0 时,为定时 器;C/T0=1 时,为计数器。 9 M1 和 M0 (Mode)(位 1 和位 0):定时/计数器 0 方式选择位(详细见表 11-2 介绍)。 表 11-2 定时/计数方式选择位设定 M0 M1 方式 备注 0 0 0 13 位定时/计数器,由 THx 的 8 位和 TLx 的低 5 位组 成,其初值计算公式为:213-n。(n 为要计数的个数 或定时值) 0 1 1 16 位定时/计数器,由 THx 的 8 位和 TLx 的 8 位组成, 其初值计算公式为:216-n。 1 0 2 8 位自动重装定时/计数器,TLx 寄存器用来计数,THx 寄存器作为重装值保持不变,当 TLx 发生溢出时,初 值自动从 THx 中重装入 TLx 中。TLx 与 THx 寄存器 的初值为:28-n。 1 1 3 此模式较为特殊,定时/计数器 0 的两个计数寄存器 TH0 和 TL0 将各自独立。TL0 可以用作 8 位定时/计 数器,其控制寄存器为 T/C0 的控制寄存器;TH0 可 以用作 8 位定时器(不能用作计数器),其控制寄存 器为 T/C1 的控制寄存器。 此模式可在定时器 1 用作波特率发生器时让定时器 0 作为 2 个 8 位定时器使用,从而能够多出一个可用的 定时器。 (2)定时/计数器控制寄存器 TCON 表 11-3 TCON 寄存器中外部中断的各功能位 位 7 6 5 4 3 2 1 0 TCON (88H) 功能 TF1 TR1 TF0 TR0 - - - - Maplead MCU Development Board http://shop63914145.taobao.com 49 9 TF1(Timer/Counter1 Flag ):定 时 /计数器 1 溢出标志位。当定时/计数器 1 溢出时,由内部硬件电路置位申请中断。当进入中断服务程序后由内部 硬件电路自动清零。 9 TR1(Timer/Counter1 Run):定时/计数器 1 运行控制位。软件控制其置位 后,定时/计数器 1 开始工作;软件将其清零后,定时/计数器 1 停止工 作。 9 TF0(Timer/Counter0 Flag ):定 时 /计数器 0 溢出标志位。当定时/计数器 0 溢出时,由内部硬件电路置位申请中断。当进入中断服务程序后由内部 硬件电路自动清零。 9 TR0(Timer/Counter0 Run):定时/计数器 0 运行控制位。软件控制其置位 后,定时/计数器 0 开始工作;软件将其清零后,定时/计数器 0 停止工 作。 定时/计数器的设定及使用 51 单片机定时器的设定及使用流程为: (1)设定定时/计数器的工作模式(M0,M1 的设定)。 (2)计数初值的初始化(THx,TLx 的设定)。 (3)中断模式则开中断。 (4)启动定时/计数器,TRx=1。 定时/计数器 0、1 演示程序 例程 11-1 定时/计数器 0、1 演示程序 /****************************************************************************** * (1)晶振 12MHz。 * (2)定时器 0 工作在方式 1;定时器 1 工作在方式 2 * (3)数码管左侧四位显示定时器 0 计数值,0~99,每秒数字增加一次 * (4)数码管右侧四位显示定时器 1 计数值,0~99,每 0.2 秒数字增加一次 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};//数码管显示段码 Maplead MCU Development Board http://shop63914145.taobao.com 50 unsigned char code LED_Bit[]={0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00};//数码管显示位 码 unsigned char T0_50ms=0; //50ms 的个数,凑成 1s 计数 unsigned int T1_200us=0; //200us 的个数,凑成 0.2s 计数 unsigned char T0_Cnt=0, T1_Cnt=0; //定时计数 void Display(unsigned char, unsigned char); //显示函数 void main(void) { TMOD=0x21; //定时器 1 工作在方式 2;定时器 0 工作在方式 1 TH0=0x3C; //定时器 0 为 16 位定时器,初值为 0x3CB0,定时间隔为 50ms TL0=0xB0; TH1 =0x38; //定时器 1 为自动重装定时器,TH 装初值后不变,TL 溢出后,TH 值自动 //装入 TL 中 TL1 =0x38; //定时间隔为 200us ET0=1; //定时器 0 中断允许 ET1=1; //定时器 1 中断允许 EA =1; //开 CPU 总中断 TR0=1; //T0 开始计时 TR1=1; //T1 开始计时 while(1) { Display(T0_Cnt, T1_Cnt); } } /****************************************************************************** * T0中断处理函数 ******************************************************************************/ void Timer0_ISR() interrupt 1 using 1 { TH0=0x3C; //装初值 TL0=0xB0; T0_50ms++; if(T0_50ms>=20) //定时 50*20 ms 后 T0_Cnt 增 1;T0_50ms 清零 { Maplead MCU Development Board http://shop63914145.taobao.com 51 T0_50ms=0; T0_Cnt++; if(T0_Cnt>=100) //99s 后,T0_Cnt 清零 T0_Cnt=0; } } /****************************************************************************** * T1中断处理函数 ******************************************************************************/ void Timer1_ISR() interrupt 3 using 2 { //因为是自动重装所以中断处理程序中不需要装初值 T1_200us++; if(T1_200us>=1000) //定时 1000*200 us 后 T1_Cnt 增 1;T1_200us 清零 { T1_200us=0; T1_Cnt++; if(T1_Cnt>=100) //99 次后,T1_Cnt 清零 T1_Cnt=0; } } /****************************************************************************** * 数字显示函数 ******************************************************************************/ void Display(unsigned char T0_No, unsigned char T1_No) { unsigned char T0_Single, T0_Tens, T1_Single, T1_Tens, i; T0_Tens =T0_No/10; //计算 T0 计数的十位值 T0_Single=T0_No-T0_Tens*10; //计算 T0 计数的个位值 T1_Tens =T1_No/10; T1_Single=T1_No-T1_Tens*10; /********************************************************** * T0计数值显示 **********************************************************/ P0=0x00; //清除数码管显示 P2=LED_Bit[0]; P0=LED_Seg[0]; //第 1 位显示“0” for(i=0;i<200;i++); P0=0x00; Maplead MCU Development Board http://shop63914145.taobao.com 52 P2=LED_Bit[1]; P0=0x40; //第 2 位显示“-” for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[2]; //第 3 位显示 T0 计数十位数 if(T0_No>=10) //如果数字大于 10 则显示十位,否则不显示十位 P0=LED_Seg[T0_Tens]; else P0=0x00; for(i=0;i<200;i++); P0=0x00; //第 4 位显示 T0 计数个位数 P2=LED_Bit[3]; P0=LED_Seg[T0_Single]; for(i=0;i<200;i++); /********************************************************* * T1计数值显示 *********************************************************/ P0=0x00; //清除数码管显示 P2=LED_Bit[4]; P0=LED_Seg[1]; //第 5 位显示“1” for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[5]; P0=0x40; //第 6 位显示“-” for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[6]; //第 7 位显示 T1 计数十位数 if(T1_No>=10) //如果数字大于 10 则显示十位,否则不显示十位 P0=LED_Seg[T1_Tens]; else P0=0x00; for(i=0;i<200;i++); P0=0x00; //第 8 位显示 T1 计数个位数 P2=LED_Bit[7]; P0=LED_Seg[T1_Single]; for(i=0;i<200;i++); } Maplead MCU Development Board http://shop63914145.taobao.com 53 12.单片机串口通信 51 单片机串行通信 并行通信是每次将一个 8 位、16 位或者 32 位等数据一次传输的通信方式; 串行通信是每次只传输数据的 1 个位的通信方式。 串行通信方式相比并行通信方式而言传输数据只需要两条数据线,更加经济 简单,而且大大减少了数据传输过程中的串扰现象,更利于长距离通信。所以串 行通信方式在近几年得以快速发展,在各种通信领域中发挥重要作用。 51 单片机的串行通信接口为 RS232 接口,是一个全双工异步串行接口 (UART)。8051 系列单片机的串行接口可以与 PC 机的 COM 接口进行通信,从 而可以实现单片机的 PC 上位机控制。 51 单片机的串行数据输入口为 P3.0 口(RXD);串行数据输出口为 P3.1 口 (TXD)。 51 单片机串行通信控制寄存器 表 12-1 51 单片机串行端口控制寄存器 SCON 位 7 6 5 4 3 2 1 0 SCON (98H) 功能 SM0 SM1 SM2 REN TB8 RB8 TI RI 9 SM0、SM1:串行口工作方式选择位。 表 12-2 SM0、SM1 指定串口工作方式 SM0 SM1 工作方式 功能描述 波特率 0 0 方式 0 8 位移位寄存器 fosc/12 0 1 方式 1 10 位 UART 由定时器决定 1 0 方式 2 11 位 UART fosc/64 或 fosc/32 1 1 方式 3 11 位 UART 由定时器决定 9 SM2:多机通信控制位。主要用于方式 2,3 中。 方式 0 不用此位应设此位为 0; 方式 1 下此位也应设置为 0,此时单片机只有接收到停止位后才置位 RI 位, 并引发中断; Maplead MCU Development Board http://shop63914145.taobao.com 54 方式 2,3 中,当 SM2 清零后,串口以单机方式发送或者接收数据,无论数 据的第 9 位(RB8)为 0 还是 1,都能够使 RI 被激活,并引起中断; 方式 2,3 中,当 SM2 置位后,只有接收到的第 9 位数据(RB8)为为 1 时才 能置位 RI,并引发中断。当接收到的第 9 位数据为 0 时,不置位 RI,接收到的 数据丢失。 9 REN:接收允许控制位。由软件控制,置位则开始接收数据,清零则停止接 收数据。 9 TB8:方式 2、3 时,本位为第 9 位传送位,由软件设置。 9 RB8:接收到数据的第 9 位。 方式 0 不使用该位; 方式 1 中,如果 SM2=0,该位为接收到的停止位; 方式 2,3 中,该位为接收到的数据的第 9 位; 9 TI:发送中断标志。当数据发送完成后该位置位,并引发中断。该位由硬件 置位,必须由软件清零。 9 RI:接收中断标志。当数据接收完成后该位置位,并引发中断。该位由硬件 置位,必须由软件清零。 表 12-3 电源控制寄存器 PCON 位 7 6 5 4 3 2 1 0 PCON (87H) 功能 SMOD - - - GF1 GF0 PD IDL 9 SMOD:波特率加倍位。当串口的波特率由 T1 产生时,该位置位则串 口波特率提高一倍。 9 GF1:通用标志位。 9 GF2:通用标志位。 9 PD:此位置位后,单片机进入掉电模式,只能由硬件复位。 9 IDL :此位置位后,单片机进入空闲模式。 Maplead MCU Development Board http://shop63914145.taobao.com 55 串口工作模式解析 1. 方式 0 在方式 0 下,串口的 SBUF 为一个同步移位寄存器。发送数据时,数据由 RxD 引脚串行输入/输出,TxD 发出移位脉冲。8 位数据发送/接收时,低位在前, 高位在后。发送/接收完一帧数据后,TI/RI 由硬件置位,并在中断允许的情况下 向 CPU 请求中断。 2. 方式 1 方式 1 为波特率可变的 10 位异步串行通信接口。10 位数据包括一个起始位 0,8 个数据位,1 个停止位 1。其传输的波特率由 T1 的溢出率决定(波特率=T1 溢出率)。 当 TI=0 时,8 位数据可以送入 SBUF 寄存器中,TxD 便将包括起始位和停 止位的 8 位数据发送出去,发送完成后 TI 置位,如果在中断允许的条件下,引 发 CPU 中断,提醒 CPU 数据发送已经完成。 当 RI=0,且 REN=1 时,串行口采样 RxD 引脚,当采样到 1 至 0 的跳变并 确认为起始位后,就开始接收一帧数据。只有当 RI=0 且停止位为 1(或者 SM2=0) 时,停止位才进入 RB8,8 位数据才进入接收寄存器,并由硬件置位中断标志 RI,否则信息丢失。所以,在方式 1 接收数据时,应该先用软件清零 RI 和 SM2 标志。 3. 方式 2 方式 2 为固定波特率的 11 位 UART 方式,它仅比方式 1 增加了一个可由软 件改变的第 9 位数据。 方式 2 发送数据时,数据由 TxD 端口输出一帧 11 位信息,包括起始位,8 位数据,由 SCON 寄存器 TB8 决定的第 9 位数据,停止位。当 11 位数据发送完 成后,硬件置位 TI 位,如果允许中断则引发中断过程。 当 REN=1 时,串口串行口采样 RxD 引脚,当采样到 1 至 0 的跳变并确认为 起始位后,就开始接收一帧数据。 当 SM2=0 时,无论接收到的第 9 位为 1 还是 0,硬件都置位 RI,并将接收 到的 8 位数据送入 SBUF 寄存器。 当 SM2=1 时,只有接收到的第 9 位数据为 1 时才能引发硬件置位 RI 位,8 位数据送入 SBUF 寄存器,第 9 为数据送入 RB8。如果在中断允许的情况下引发 Maplead MCU Development Board http://shop63914145.taobao.com 56 中断。 4. 方式 3 方式 3 为波特率可变的 11 位 UART 方式。除波特率由定时器 1 的溢出率决 定外,其它与方式 2 相同。 串口波特率计算 在方式 1 和方式 3 中,使用定时器 1 来产生波特率,由于串口定时要求比较 严格,因此一般采用定时器 1 的可自动重装的方式 2 进行计时。在定时器 1 方式 2 下,传输波特率计算公式为: 根据此式便可推导出在一定波特率下正确的定时器 1 初值。值得注意的是, 当波特率加倍位开启后,最终的波特率应该为上式数值的两倍。 串口初始化步骤 串口初始化过程一般为:(方式 0,2 不必设定 T1,前 4 步可省去) (1) T1 工作方式确定(TMOD)。 (2) TH1,TL1 初值设定。 (3) 启动定时器 1(TR1=1)。 (4) 设定波特率加倍位。 (5) 串口工作方式确定,允许接收(SCON)。 (6) 总中断使能(不使用中断方式可不启动总中断)。 单片机串口通信演示程序 例程 12-1 串口通信演示程序 /****************************************************************************** (1)串口通信例程,采用循环查询方式,不采用中断方式。 (2)将开发板的 USB 转串口线连接至 PC 电脑,查明开发板连接的 COM 口编号,打开串口调试助手,设定好对应的 COM 编号,设定波特率 为 9600。 (3)发送十进制数据或者 16 进制数据至单片机,如果发送的数据 为 1,则单片机在接收到此数据后,自动回发 Hello World!字符串 12 12 256 32 SMOD osc baud ff ⎛⎞=× ×⎜⎟−⎝⎠初值 Maplead MCU Development Board http://shop63914145.taobao.com 57 至 PC 机,并在串口调试助手中显示。注意,接收显示框应该以文本 方式显示,否则显示的是字符串的 ASC 码制序列。 (4)PC 机发送给单片机的数据会在开发板数码管上显示。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include void UART_Init(void); void Display(unsigned char); unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; //数码管段码 unsigned char code LED_Bit[]={0x00, 0x01}; //数码管位码 void main(void) { unsigned char i, Data_R, Data_T[]="Hello World!"; UART_Init(); while(1) { if(RI) //如果串口收到数据 { RI=0; //接收标志清零 Data_R=SBUF; if(Data_R==0x01) //如果接收到的数据为 0x01,则通过串口发送 //"Hello World!" { for(i=0;i<12;i++) { SBUF=Data_T[i]; while(!TI); //循环等待一个字节数据发送完毕 TI=0; //发送标志清零 } } } Display(Data_R); //LED 上显示接收到的数据 } } /*************************************************************** * 串口通信初始化函数 ****************************************************************/ void UART_Init(void) { TMOD=0x20; //T1 方式 2 TH1 =0xFD; //装初值,波特率为 9600 TL1 =0xFD; TR1 =1; //启动 T1 Maplead MCU Development Board http://shop63914145.taobao.com 58 SCON=0x50; //串口通信方式 1 } /*************************************************************** * 数码管显示函数 ****************************************************************/ void Display(unsigned char Num) { unsigned char First_Bit, Second_Bit, i; First_Bit =Num%16; //取出 16 进制低位 Second_Bit=Num/16; //取出 16 进制高位 P0=0x00; //清数码管显示 P2=LED_Bit[0]; P0=LED_Seg[First_Bit]; //显示 16 进制低位 for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[Second_Bit]; //显示 16 进制高位 for(i=0;i<200;i++); } Maplead MCU Development Board http://shop63914145.taobao.com 59 13.1602 液晶显示 1602 液晶接口 图 13-1 1602 液晶接口 1602 液晶显示屏共有 16 个引脚,各引脚定义见下表: 表 13-1 1602 液晶引脚定义 编号 符号 引脚说明 编号 符号 引脚说明 1 VSS 电源地 9 D2 并口数据第 2 位 2 VCC 电源正 10 D3 并口数据第 3 位 3 V0 对比度调节 11 D4 并口数据第 4 位 4 RS 数据/命令选择端(H/L) 12 D5 并口数据第 5 位 5 R/W 读/写选择端(H/L) 13 D6 并口数据第 6 位 6 E 使能端 14 D7 并口数据第 7 位 7 D0 并口数据第 0 位 15 BL+ 背光正极 8 D1 并口数据第 1 位 16 BL- 背光负极 1602 液晶显示原理 1602 内置了内置了 DDRAM、CGROM 和 CGRAM。 DDRAM 是显示数据 RAM,用来存放要显示的字符的代码。它的地址与屏 幕显示的对应关系如下所示: Maplead MCU Development Board http://shop63914145.taobao.com 60 表 13-2 DDRAM 与屏幕显示位置对应表 显示位置 1 2 3 4 5 6 7 …… 40 第一行 00H 01H 02H 03H 04H 05H 06H …… 27H DDRAM 地址 第二行 40H 41H 42H 43H 44H 45H 46H …… 67H 如果要在 1602 液晶屏幕的第一行第一列显示一个"A"字,就要向 DDRAM 的 00H 地址写入“A”字的代码就行了。每一行有 40 个地址,只用到了前 16 个, 其余的在显示中没有用到。第二行也一样用前 16 个地址。所以,最终 1602 两行 所对应的地址为: 表 13-3 DDRAM 与屏幕显示位置对应表 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 1602 液晶模块内部的字符发生存储器(CGROM)已经存储了 160 个不同的 点阵字符图形,每一个字符都有一个固定的代码。表中第一行的 4 位 2 进制数表 示字符编码的高 4 位,第一列竖行的 4 位 2 进制数表示字符码的低 4 位。比如大 写的英文字母“A”的代码是 01000001B(41H),显示时模块把地址 41H 中的点阵 字符图形显示出来,我们就能看到字母“A”。 表 13-3 显示了 1602 液晶模块中字库及其代码,表中所列的字符代码与我们 在 PC 机中用到的字符代码是基本一致的。因此我们在向 DDRAM 写 C51 字符 代码程序时甚至可以直接用 P1='A'这样的方法。C 语言在编译时就把“A”先转为 41H 代码了。 字符代码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字符, 可以存放 8 组,5X10 点阵的字符,存放 4 组),为 CGRAM。 0x20~0x7F 为标准的 ASCII 码,0xA0~0xFF 为日文字符和希腊文字符,其 余字符码(0x10~0x1F 及 0x80~0x9F)没有定义。 Maplead MCU Development Board http://shop63914145.taobao.com 61 表 13-3 CGROM 中各字符编码与 CGRAM 对应地址表 1602 液晶指令详解 1602 液晶共有 11 条指令,其指令详细介绍如下: 1. 清屏指令 表 13-4 清屏指令各位值 功能: Maplead MCU Development Board http://shop63914145.taobao.com 62 (1)清除液晶显示器,即将 DDRAM 的内容全部填入"空白"的 ASCII 码 20H。 (2)光标归位,即将光标撤回液晶显示屏的左上方。 (3)将地址计数器(AC)的值设为 0。 解析: 采用写命令的形式向 1602 液晶发送命令码 0x01,则 1602 液晶被清屏,光 标归位,地址值复位为 0 地址。 2. 光标归位指令 表 13-4 光标归位指令各位值 功能: (1)把光标撤回到显示器的左上方。 (2)把地址计数器(AC)的值设置为 0。 (3)保持 DDRAM 的内容不变。 (4)DB0 位的 X 表示此位可以为任何值,0 或 1 都可以。 解析: 采用写命令的形式向 1602 液晶发送命令码 0x02 或 0x03,则 1602 液晶光标 归位到 0 地址处,地址计数器复位为 0 地址。 3. 写入模式设置指令 Maplead MCU Development Board http://shop63914145.taobao.com 63 功能: 设定每次写入 1 位数据后光标的移位方向,并且设定每次写入的一个字符是 否移动。参数设定的情况如下所示: 位名 设置 I/D 0=写入新数据后光标左移 1=写入新数据后光标右移 S 0=写入新数据后原显示内容不移动 1=写入新数据后显示内容整体右移 1 个字 符 解析: 采用写命令的形式向 1602 液晶发送命令码(0x04|0x00)或(0x04|0x01)或 (0x04|0x02)或(0x04|0x03),则 1602 液晶光标会按照设定方式移动,写入新数据 后,整屏的原显示内容被设定为移动或者不移动。 例如,我们要设定 1602 液晶光标写入新数据后向右移动,写入新数据后原 来显示的内容不移动,则指令的 I/D 位应设定为 1,S 位应设定为 0。数据总线 上指令的二进制码为(0000 0 1 1 0 ),其 16 进制码为 0x06。 4. 显示开关控制指令 功能: 控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情况如下: 位名 设置 D 0=显示功能关 1=显示功能开 C 0=无光标 1=有光标 B 0=光标闪烁 1=光标不闪烁 解析: 采用写命令的形式向 1602 液晶发送命令码(0x08|0xXX)则 1602 液晶会开启/ Maplead MCU Development Board http://shop63914145.taobao.com 64 关闭液晶显示功能、开启/关闭光标、设定光标闪烁/不闪烁。 例如,我们要求 1602 液晶开启显示功能、有光标且光标闪烁,则数据总线 上写入的指令码为(0000 1 1 1 0),其对应的 16 进制数据为 0x0E。 5. 设定显示屏或光标移动方向指令 功能: 使光标移位或使整个显示屏幕移位。参数设定的情况如下: S/C R/L 设定情况 0 0 光标左移 1 格,且地址计数器 AC 值减 1 0 1 光标右移 1 格,且地址计数器 AC 值加 1 1 0 显示器上字符全部左移一格,但光标不动 1 1 显示器上字符全部右移一格,但光标不动 解析: 例如,我们要使光标右移一格,地址计数器 AC 值增加 1,则数据总线应写 入的指令码为(0001 0 1 00),其对应的 16 进制码为 0x14。 6. 功能设定指令 功能: 设定数据总线位数、显示的行数及字型。参数设定的情况如下: 位名 设置 Maplead MCU Development Board http://shop63914145.taobao.com 65 DL 0=数据总线为 4 位 1=数据总线为 8 位 N 0=显示 1 行 1=显示 2 行 F 0=5×7 点阵/每字符 1=5×10 点阵/每字符 解析: 本指令的目的是设定 1602 液晶的总线位数、显示模式。 例如,我们产用 1602 液晶屏的总线位数为 8 位、分两行显示、字符为 5×7 点阵,则 DL 为应该设定为 1,N 位应设定为 1,F 位应设定为 0,其指令码为(001 1 1 0 00),其对应的 16 进制码为 0x38,这也是 1602 程序在初始化的时候常用的指 令码。 7. 设定 CGRAM 地址指令 功能:设定下一个要存入数据的 CGRAM 的地址。 解析: 1602 液晶字符码表见表 13-3。其中字符寄存器的第一竖行的前 8 个位置是 用户可以自己定制的字符,其在字符寄存器中的地址分别为(0000 0000~0000 0111)。5×7 点阵的字符可以每个编号存一个,每个字符需要写入 8 个字节的数据 (即字模的点阵码)。5×10 点阵的字符可以存 4 个,每两个位置的编号存一个。 当需要自己定制字符时,其指令写入方法为: (1) RS=0;R/W=0; (2) DB7=0;DB6=1; (3) DB5、DB4、DB3 这 3 位表示自定义的字符码(000 ~111),对应 在字符表中的地址为(0000 0000~0000 0111)。 (4) DB2、DB1、DB0 这 3 位表示字模位置地址(即字模每个字节的 地址,000~111,共 8 个字节的点阵数据构成一个字符)。 Maplead MCU Development Board http://shop63914145.taobao.com 66 例如,我们要自定制一个字符“¥”,首先要取这个字符的字模。在字模中参 与生成字符的点为前 7 个字节中每个字节的后 5 位,显示的点记为“1”,不显示 的点记为“0”。每个字节有 8 个位,由于每个字符的高 3 位不参与字符生成,所 以每个字节的高3位都为“0”。第8个字节不参与自定义字符生成,所以记为0x00。 地址(DB2,DB1,DB0) 字符码 字符码 2 进制 000 0x11 0 0 0 1 0 0 0 1 001 0x0A 0 0 0 0 1 0 1 0 010 0x04 0 0 0 0 0 1 0 0 011 0x1F 0 0 0 1 1 1 1 1 100 0x04 0 0 0 0 0 1 0 0 101 0x04 0 0 0 0 0 1 0 0 110 0x04 0 0 0 0 0 1 0 0 111 0x00 0 0 0 0 0 0 0 0 由上表可知,字符点阵的数据码共有 8 个字节的数据组成,分别为:0x11, 0x0A,0x04,0x1F,0x04,0x04,0x04,0x00。 将此字模写入字符寄存器要分 8 次写入,每次写入的字符码地址相同 (DB5~DB3 都为同一个地址,取值范围 000~111),字模字节地址不同(分别 为 000~111),命令字写完后紧跟写入一个数据字节(即对应字模的每个字节), 写入方法参见第 10 个指令。 8. 设定 DDRAM 地址指令 功能:设定下一个要存入数据的 DDRAM 的地址。 解析: 指令码的低 7 位取值为 00H~27H,40H~67H。其中,在液晶屏上能够显示 的地址取值为 00H~0FH,40H~4FH。 指令写完后,后面要跟第 10 条写入数据的指令,写入一个字符码,以在液 晶屏上显示相应的字符。 9. 读取忙信号或 AC 地址指令 Maplead MCU Development Board http://shop63914145.taobao.com 67 功能: 读取忙碌信号 BF 的内容,BF=1 表示液晶显示器忙,暂时无法接收单片机 送来的数据或指令。当 BF=0 时,液晶显示器可以接收单片机送来的数据或指令。 读取地址计数器(AC)的内容。 在执行每条指令前,都应该读取忙信号,在确认不忙的时候才能执行相应 指令,否则写入的指令可能得不到执行。 解析: 当 R/W 信号线为高电平,RS 信号线为低电平时,表示要读取一个字节的指 令码。该指令码有两部分组成,最高位(DB7)为忙碌信号位(FB),当该位为高电 平(1)时,表示 1602 液晶目前正忙于处理数据,不接受控制器传来的指令;当该 位为低电平时,表面 1602 液晶目前空闲,可以接受控制器传过来的指令。 指令码的低 7 位是 1602 液晶目前的地址计数器的内容,可以此来判断目前 1602 液晶地址计数器指向了哪个字符位置。 10. 数据写入 DDRAM 或 CGRAM 指令 功能: 将字符码写入 DDRAM,以使液晶显示屏显示出相对应的字符。 将使用者自己设计的图形存入 CGRAM。 解析: 例如,我们要在液晶屏第一行的第一格位置显示一个“A”字,首先要用第 8 条指令写入欲显示字符的显示地址,然后再利用本条指令写入“A”字符的编码 “41H”,则液晶屏在第一行的第一格位置显示了一个“A”字。 Maplead MCU Development Board http://shop63914145.taobao.com 68 11. 从 CGRAM 或 DDRAM 读出数据指令 功能: 读取 DDRAM 或 CGRAM 中的内容。 解析: 本条指令与第 10 条指令刚好执行相反的动作。用法与第 10 条指令顺序相同, 只是本条指令会读出相应寄存器的数据,而不是写入。 1602 液晶的插接 Maplead MCU Development Board http://shop63914145.taobao.com 69 图 13-2 1602 液晶在电路板上的插接 按照图 13-2 所示,1602 插座为 16 孔的排母,1602 液晶的排针要朝上,对 齐 1602 插座的 16 个插口安装,不可错位。 图 13-3 1602 液晶背景灯控制 如图 13-3 所示,当用短路子将 1602 背景灯控制排针短接后,1602 背景灯 点亮。 图 13-4 1602 液晶对比度调节 如图 13-4 所示,通过旋钮 1602 对比度控制电阻,可以调节 1602 液晶屏的 对比度。 1602 液晶显示演示程序 例程 13-1 1602 液晶显示 /******************************************************************** Maplead MCU Development Board http://shop63914145.taobao.com 70 1602 液晶显示 晶振 12Mhz 调试通过。 * 作者:Shenney John ********************************************************************* * Copyright (C) 2010 by Shenney John, All Rights Reserved. ********************************************************************/ #include void Delay(void); bit Busy_R(void); void LCD1602_Init(void); void Cmd_W(unsigned char,bit); void Data_W(unsigned char); void Cls_Screen(void); void LCD1602_Put_Char(unsigned char, bit, unsigned char); sbit E =P2^5; sbit R_W=P2^6; sbit RS =P2^7; void main(void) { unsigned char i; unsigned char a[]="Maplead"; unsigned char b[]="80C51 MCU Board"; LCD1602_Init(); for(i=0;i<7;i++) LCD1602_Put_Char(5+i,0,a[i]); //第 1 行的第 5 个字符开始写字符串"Maplead" for(i=0;i<15;i++) LCD1602_Put_Char(i,1,b[i]); //第 2 行的第 1 个字符写"80C51 MCU Board" while(1); } /******************************************************************** 延时函数 ********************************************************************/ void Delay(void) //延时大约 5ms { unsigned int data i; for(i=0;i<1000;i++); } /******************************************************************** 读忙信号 ********************************************************************/ bit Busy_R(void) { P0=0xFF; E =0; RS =0; R_W=1; Maplead MCU Development Board http://shop63914145.taobao.com 71 if(P0 & 0x80) return 0; else return 1; } /******************************************************************** 写数据 ********************************************************************/ void Data_W(UNSIGNED CHAR Data) { Delay(); while( Busy_R() ); E =0; RS =1; R_W=0; E =1; Delay(); P0 =Data; E =0; } /******************************************************************** 写指令 ********************************************************************/ void Cmd_W(UNSIGNED CHAR Data,bit Busy) { if(Busy) while( Busy_R() ); E =0; RS =0; R_W=0; E =1; Delay(); P0 =Data; E=0; } /******************************************************************** 清屏 ********************************************************************/ void Cls_Screen(void) { Cmd_W(0x01,1); } /******************************************************************** LCM1602 初始化 ********************************************************************/ void LCD1602_Init(void) { Cmd_W(0x38,0); //显示模式设定 3 次,不检测忙信号 Delay(); Cmd_W(0x38,0); Delay(); Cmd_W(0x38,0); Maplead MCU Development Board http://shop63914145.taobao.com 72 Delay(); /********************** * 以上为固定流程 ***********************/ Cmd_W(0x38,1); //显示模式设定(8 位,两行,5*7) Cmd_W(0x0c,1); //显示开,无光标 Cmd_W(0x06,1); //光标右移 Cls_Screen(); //清屏 Delay(); } /******************************************************************** 指定位置显示一个字符 Y 为行标,Y=0 代表第一行;Y=1 代表第二行 ********************************************************************/ void LCD1602_Put_Char(unsigned char X, bit Y, unsigned char Data) { if(Y) X |=0x40; //如果是第二行,X 值加 0x40 X |=0x80; //将最高位的指令符放入 X 中 Cmd_W(X,1); //给地址 Data_W(Data); //给数据 } Maplead MCU Development Board http://shop63914145.taobao.com 73 14.12864 液晶显示 12864 液晶接口 图 14-1 12864 液晶接口 12864 液晶共有 20 个端口,各端口定义见下表: 表 14-1 12864 液晶端口定义 端口 定义 1 GND 接地。 2 VCC 接电源。 3 V0 对比度调节端。 4 RS(CS) 并行时数据(1),指令(0)选择端;串行的片选信号端。 5 R/W(SIO) 并行时读(1)写(0)信号;串行时为数据输入输出端。 6 E(CLK) 并行时使能信号;串行时同步时钟输入端。 7 D0~D3 并行数据 0~3。 11 D4~D7 并行数据 4~7;4 位并口时空接。 15 PSB 并口(1)串口(0)选择。 16 NC 空。 17 RST 复位,低电平有效。 18 VEE 液晶驱动电压输出端。 19 BL+ 背光阳极。 20 BL- 背光阴极。 12864 液晶内部控制结构 12864 液晶屏是由 128*64 个“点”组成的。这些“点”分成了 64 行,每行有 128 Maplead MCU Development Board http://shop63914145.taobao.com 74 个“点”。通过程序,可以给每个“点”对应的地址空间赋值 1 或者 0 就能够在该点 分别显示“黑点”或者“白点”,从而能够在屏幕上显示相应的字符或者图像。 从图 14-3 我们可以直观地看到一个汉字的显示构成。 1602 内置了内置了 CGROM、HCGROM、CGRAM、DDRAM 和 GDRAM 5 个存储器。其中 2 个只读存储器(ROM)中存放了字符的信息,3 个可读写存 储器(RAM)可由用户指定其中的内容。 CGROM: 12864 液晶 CGROM 中固化了 GB 简体中文字库,包含 8192 个简体汉字。 每个汉字由 16×16 点阵构成,也就是说每个汉字占用 16×16=256 个点。所以 12864 液晶每行能够显示 128÷16=8 个汉字,总共能够显示汉字 64÷16=4 行。其编码范 围为 A140H~D75FH(BIG5),A1A0H~F7FFH(GB)。 HCGROM: 图 14-2 HCGROM 中的 16*8 半宽字型 12864 液晶 HCGROM 中固化了 128 个 16×8 点阵的半字宽 ASCII 字符。12864 液晶每行能够显示 ASCII 字符 128÷8=16 个,总共能够显示 ASCII 字符 64÷16=4 行。其编码范围为 02H~7FH。 CGRAM: 12864 液晶包含 4 组 16*16 点阵(每组包含 16×2 字节存储器)用户自定义 字符存储器 CGRAM。当需要显示的字符无法在汉字库及 ASCII 字库中找到时, 就可以使用这些字符生成存储器进行自造字符。所造字符的编码可以是 0000H、 Maplead MCU Development Board http://shop63914145.taobao.com 75 0002H、0004H、0006H。 如图 14-3 所示,用 CGRAM 的第 0000H 单元与第 0002H 单元自造了两个字 符。在每个 CGRAM 单元内部有地址为 00H~0FH 的 16 个存储地址,每个存储 地址对应 2 个欲显示字符的 8 位编码,分别为高位字节与低位字节。在 CGRAM 中存储的字节的每一位都对应着屏幕上显示的一个点,当某位为 1 时,在屏幕上 对应的点就显示为黑色,否则就不显示(或者说白色)。 图 14-3 CGRAM 自造字存储器 X 表示该位值可为 0,可为 1; DDRAM 字元代码:自造字符编码; CGRAM 位址 :共 6 位,高 2 位表示自造字符编码,低 4 位表示 CGRAM 中各个编码地址; 高位元组 :一个字符地址的高 8 位; 低位元组 :一个字符地址的低 8 位。 DDRAM: 12864 液晶包含 64×2 字节的显示 RAM 存储器,每个地址单元能够存储两个 字节数据,可以理解为 1 个 16 位数据。该组存储器每个地址包含 2 字节的存储 空间,可以用来显示汉字(CGROM 中的字符)、ASCII 字符(HCGROM 中的字 Maplead MCU Development Board http://shop63914145.taobao.com 76 符)以及 CGRAM 自造字符(CGRAM 中的字符)。DDRAM 的前 32 个地址与屏 幕上的汉字显示位置一一对应,如表 14-2 所示。例如,要在液晶屏的第 1 行的 第一个位置显示一个汉字,则用写 DDRAM 指令将相应的汉字编码(两个字节 组成,分为高 8 位和低 8 位)写入 DDRAM 的 00H 单元就可以了。 HCGROM 中 1 个 ASCII 码字符只有 1 个字节构成。因此,1 个 DDRAM 地 址单元可以存储 2 个 ASCII 码字符的编码。相应的,在屏幕上一个汉字的显示 位置就能够显示 2 个 ASCII 码字符(因为其点阵为 16×8,高度与汉字相同,但 是宽度窄了一半)。因为一个地址显示两个 ASCII 字符,所以,ASCII 字符不能 很灵活地指定到屏幕上的每一个位置,而只能用间接的方法写入。例如,第 1 行的第 2 个 ASCII 字符位置只能先写入第 1 个字符后再写入第 2 个字符。如第 1 个字符位置不显示则直接将第 1 个字符位置写入空格,如第 1 个字符位置原来有 字符,则需先读出原来的字符后再跟第 2 个字符一起写入。 值得注意的是,地址单元的编排与屏幕显示位置并不按顺序对应。第一行最 后一个位置的地址为 07H,它的下一个地址 08H 并不是第 2 行的第 1 个字符位 置,而是第 3 行第 1 个字符的位置。直观上感觉,第 2 行和第 3 行对应的 DDRAM 地址似乎搞反了。因此,当我们往屏幕上写字符的时候只能一行一行地写,而不 能图省事,将 32 个字符存于一个数组中,一股脑从第 00H 地址写到第 1FH 地址。 这样的结果是,本应在第 2 行显示的字符跑到了第 3 行,而第 2 行却显示了第 3 行的内容。 表 14-2 液晶屏显示位置与 DDRAM 地址对应关系 行 列 第 1 行 00H 01H 02H 03 H 04 H 05 H 06 H 07 H 第 2 行 10H 11H 12H 13H 14H 15H 16H 17H 第 3 行 08H 09H 0AH 0BH 0CH 0DH 0EH 0FH 第 4 行 18H 19H 1AH 1BH 1CH 1DH 1EH 1FH GDRAM: 12864 液晶拥有能够进行点阵黑白图像显示的绘图存储器 GDRAM。 GDRAM 的结构如图 14-4 所示。 GDRAM 由 64×16 个存储单元构成,分为 64 行,16 列。每个存储单元为 2 个字节构成(可以理解为一个 16 位存储单元),分为高 8 位和低 8 位。每个存储 单元的字节在屏幕上对应着 16 个点,当某个位为“1”时,改点显示为黑色,为“0” 时,不显示。 Maplead MCU Development Board http://shop63914145.taobao.com 77 GDRAM 寄存器中并不是所有的内容都用来显示的。其中,垂直坐标(Y) 的 0~32 为液晶有效显示的区域。水平坐标(X)的 0~7(每个单元为 16 位数) 区域为 12864 液晶的上半屏显示的内容,而水平坐标的 8~15 区域为 12864 液晶 的下半屏显示的内容。 图 14-4 GDRAM 的结构 图 14-4 GDRAM 绘图存储器 12864 液晶指令详解 基本指令集: 1. 清屏指令 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 0 1 Maplead MCU Development Board http://shop63914145.taobao.com 78 发送该指令后,整个屏幕原来显示的内容被清除。 2. 地址归零 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 1 X DDRAM 中的内容不变,但是游标归零。意即下一个写入或读出的数据都是 从 DDRAM 的 00H 单元开始的。 3. 进入设定点 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 1 I/D S 设定光标移动方向,并指定整体显示是否移动。 I/D=0,光标右移,AC 自动加 1;I/D=1,光标左移,AC 自动减 1。 S=0,DDRAM 为读状态,整体显示不移动,S=1,DDRAM 为写状态,整 体显示移动,移动方向由 I/D 位决定。 4. 显示开关 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 1 D C B 当 D、C、B 位为 0 时,该位的功能关闭,为 1 则该位的功能开启。 D 位:整体显示开关位; C 位:光标显示开关位; B 位:光标反白闪烁位。 5. 光标或显示移位控制 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 1 S/C R/L X X S/C 屏幕(1)或光标(0)移动控制位。 R/L 为屏幕或光标向左(0)或向右(1)移动。 AC 值不变。 6. 功能设定 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 Maplead MCU Development Board http://shop63914145.taobao.com 79 0 0 0 0 1 DL X RE X X DL=1: 8-BIT 控制接口;DL=0: 4-BIT 控制接口。 RE=1: 扩充指令集动作;RE=0: 基本指令集动作。 7. 设定 CGRAM 地址 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 1 AC5 AC4 AC3 AC2 AC1 AC0 AC5~AC4:指定自造字符的外部寻址地址。 AC3~AC0:指定 CGRAM 一个单元内部的 16 个字节地址。 8. DDRAM 寻址 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 1 AC6 AC5 AC4 AC3 AC2 AC1 AC0 设定 DDRAM 地址至地址计数器 AC。 9. 读忙 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 1 BF AC6 AC5 AC4 AC3 AC2 AC1 AC0 读忙状态,当 BF=0 时,液晶处于闲状态,才能进行读写操作。 AC6~AC0:AC 计数器的当前值。 10. 写资料到 RAM RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 1 0 DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 DDRAM寻址指令后,连续用该指令两次写入一个 DDRAM 单元值,写入 顺序由低位至高位。 11. 读 RAM 资料 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 1 1 DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 从内部 RAM 读取数据(DDRAM/CGRAM/GDRAM),当设定地址指令后, 若需读取数据时需先执行一次空的读数据,才会读取到正确数据,第二次读取时 则不需要,除非又下设定地址指令。 Maplead MCU Development Board http://shop63914145.taobao.com 80 扩充指令集(功能设定指令中的 RE 位设定为 1,接下来的操作不改变该位则维 持扩充指令状态,不需每次都进行改变): 1. 待命模式 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 0 1 执行该指令后,12864 液晶处于待命模式,执行一次任何其它指令都能终止 待命模式。 2. 卷动位置或者 RAM 地址选择 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 1 SR 当 SR=1 时,允许输入垂直卷动地址。 当 SR=0 时,允许设定 CGRAM 地址(基本指令)。 3. 反白显示 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 1 R1 R0 R0=0,第一三行反白显示,再次执行为正常显示。 R0=1,第二四行反白显示,再次执行为正常显示。 4. 睡眠模式 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 1 SL X X SL=0,进入睡眠模式; SL=1,推出睡眠模式。 5. 扩充功能设定 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 1 DL X RE G X DL:8/4 位接口控制位。DL=1,8 位 MPU 接口;DL=1,4 位 MPU 接口。 RE:指令集选择控制位。RE=1,扩充指令集;RE=0,基本指令集。 G:绘图显示控制位。G=1,绘图显示开;G=0,绘图显示关。 Maplead MCU Development Board http://shop63914145.taobao.com 81 同一指令的动作不能同时改变 RE 及 DL、G,需先改变 DL 或 G 再改变 RE 才能确保设置正确。 6. 设定卷动地址 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 1 AC5 AC4 AC3 AC2 AC1 AC0 SR=1,AC5~AC0 为垂直卷动地址。 7. 设定绘图 RAM 地址 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 1 AC6 AC5 AC4 AC3 AC2 AC1 AC0 RW RS DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 1 0 0 0 AC3 AC2 AC1 AC0 设定 GDRAM 地址到地址计数器(AC),先设置垂直位置再设置水平位 置,连续写入 2 字节数据来完成垂直与水平坐标的设置。 垂直地址范围:AC6~AC0。 水平地址范围:AC3~AC0。 12864 液晶在开发板上的安装 图 14-5 12864 液晶在开发板上的安装 Maplead MCU Development Board http://shop63914145.taobao.com 82 12864 液晶插座为 20 孔的排母,液晶安装的时候应该将排针朝上,对齐插 座安装,不可错位。 注意:12864 液晶此时显示的内容是反的,观看时应该将开发板旋转 180 度。 图 14-6 12864 液晶背景灯控制 如图 14-6 所示,当用短路子将 12864 背景灯控制排针短接后,12864 背景 灯点亮。 因为 12864 液晶耗电量较大,当采用 USB 供电时,点亮液晶的背景灯可能 使得液晶的对比度变得非常差,因此建议采用 USB 供电时尽量不要打开液晶的 背景灯。 当使用负载能力较大的外部电源后,点亮 12864 背景灯才不影响液晶显示的 对比度。 图 14-7 12864 液晶对比度调节 Maplead MCU Development Board http://shop63914145.taobao.com 83 如图 14-7 所示,通过旋钮 12864 对比度控制电阻,可以调节 12864 液晶屏 的对比度。 12864 液晶显示演示程序 例程 14-1 1602 液晶文字显示 /******************************************************************** * (1)晶振 12Mhz 调试通过。 * (2)Keil 软件处理汉字编码时有 bug,“三”,“正”等字没法正确显示, * 具体处理方法见配套程序文件夹。 * 作者:Shenney John ********************************************************************* * Copyright (C) 2010 by Shenney John, All Rights Reserved. ********************************************************************/ #include #include #define LCDData P0 //LCD 并行数据口 sbit DS1302=P1^2; //DS1302 复位端 sbit RS =P2^7; //数据指令选择端 sbit RW =P2^6; //读写选择端 sbit E =P2^5; //并行使能信号端 sbit PSB=P2^4; //并行串行选择端 sbit RST=P2^3; //复位端 void Disp_Str(unsigned char *, unsigned char); //字符显示 void Send_Data(unsigned char); //送数据 void Send_CMD(unsigned char); //送指令 void Check_Busy(void); //读忙 void LCD_Init(void); //1602 初始化 void Delay5ms(void); //延时 5ms void Delay4s(void); //延时 4s /************************************************ * 字符串 *************************************************/ unsigned char code str_1[] = "深圳迈普利科技!"; unsigned char code str_2[] = " 液晶演示程序"; unsigned char code str_3[] = " ABCDabcd"; Maplead MCU Development Board http://shop63914145.taobao.com 84 unsigned char code str_4[] = " 12345678"; unsigned char code str_5[] = "竹外桃花三两枝,"; unsigned char code str_6[] = "春江水暖鸭先知。"; unsigned char code str_7[] = "蒌蒿满地芦芽短,"; unsigned char code str_8[] = "正是河豚欲上时。"; void main(void) { DS1302=0; //关闭 DS1302 输入输出防止误动作 LCD_Init(); while(1) { Send_CMD(0x01); //清屏 Disp_Str(str_1, 1); Disp_Str(str_2, 2); Disp_Str(str_3, 3); Disp_Str(str_4, 4); Delay4s(); Send_CMD(0x01); //清屏 Disp_Str(str_5, 1); Disp_Str(str_6, 2); Disp_Str(str_7, 3); Disp_Str(str_8, 4); Delay4s(); } } /************************************************ * 显示字符串 *************************************************/ void Disp_Str(unsigned char *str, unsigned char line) { unsigned char Addr,i,StrLenth; if(line==1) Maplead MCU Development Board http://shop63914145.taobao.com 85 Addr=0x80; //第一行地址为 0x80 else if(line==2) Addr=0x90; //第二行地址为 0x90 else if(line==3) Addr=0x88; //第三行地址为 0x88 else if(line==4) Addr=0x98; //第三行地址为 0x98 else Addr=0x80; //如果行号不属于 1~4,默认为 1 StrLenth=( unsigned char)strlen(str);//取字符串长度 Send_CMD(Addr); //送字符串显示首地址 Delay5ms(); for(i=0;i #include #define LCDData P0 //LCD 并行数据口 sbit DS1302=P1^2; //DS1302 复位端 sbit RS =P2^7; //数据指令选择端 Maplead MCU Development Board http://shop63914145.taobao.com 88 sbit RW =P2^6; //读写选择端 sbit E =P2^5; //并行使能信号端 sbit PSB=P2^4; //并行串行选择端 sbit RST=P2^3; //复位端 void Disp_Pic(unsigned char *); //图像显示 void Send_Data(unsigned char); //送数据 void Send_CMD(unsigned char); //送指令 void Check_Busy(void); //读忙 void LCD_Init(void); //1602 初始化 void Delay5ms(void); //延时 5ms void Delay4s(void); //延时 4s void main(void) { DS1302=0; //关闭 DS1302 输入输出防止误动作 LCD_Init(); while(1) { Disp_Pic(pic1); Delay4s(); Disp_Pic(pic2); Delay4s(); Disp_Pic(pic3); Delay4s(); Disp_Pic(pic4); Delay4s(); } } /************************************************ * 12864图形显示初始化 *************************************************/ void LCD_Init(void) { Maplead MCU Development Board http://shop63914145.taobao.com 89 Delay5ms(); RST=1; Delay5ms(); RST=0; Delay5ms(); RST=1; Delay5ms(); Send_CMD(0x34); //8 位接口,基本指令集 Delay5ms(); Send_CMD(0x34); Delay5ms(); Send_CMD(0x36); //用扩充指令开图像显示 Delay5ms(); Send_CMD(0x01); //清屏 Delay5ms(); } /************************************************ * 送数据 *************************************************/ void Send_Data(unsigned char Data) { Check_Busy(); //读忙 RS=1; //并行数据 RW=0; //写 E=1; //使能 12864 操作 LCDData=Data; //送数据 E=0; //关闭 12864 操作 } /************************************************ * 送命令 *************************************************/ void Send_CMD(unsigned char CmdNo) { Check_Busy(); RS=0; //并行命令 RW=0; //写 Maplead MCU Development Board http://shop63914145.taobao.com 90 E=1; //使能 12864 LCDData=CmdNo; //送命令号 E=0; //关闭 12864 } /************************************************ * 读忙 *************************************************/ void Check_Busy(void) { RS=0; //并行命令 RW=1; //读 E=0; //使能 12864 LCDData=0xFF; //置数据口为读状态 E=1; //使能 12864 while((LCDData & 0x80)==1); //测试最高位,直至为 0 } /************************************************ * 显示图像 *************************************************/ void Disp_Pic(unsigned char * pic) { unsigned char i,j; /*************************** * 显示屏幕 0~31 行图像 ****************************/ for(i=0;i<32;i++) { Send_CMD(0x80 | i); //垂直地址 0~15 Send_CMD(0x80); //水平地址,只需给出首地址 80 for(j=0;j<16;j++) //给出水平首地址后,后面每送一个数据 { //水平地址指针自动加 1 Send_Data(*pic); pic++; } } /*************************** * 显示屏幕 32~63 行图像 Maplead MCU Development Board http://shop63914145.taobao.com 91 ****************************/ for(i=0;i<32;i++) { Send_CMD(0x80 | i); //垂直地址 0~15 Send_CMD(0x88); //水平地址,只需给出首地址 88 for(j=0;j<16;j++) { Send_Data(*pic); pic++; } } } /************************************************ * 延时 5ms *************************************************/ void Delay5ms(void) { unsigned int i; for(i=0;i<932;i++); } /************************************************ * 延时 4s *************************************************/ void Delay4s(void) { unsigned int i,j; for(i=0;i<800;i++) for(j=0;j<932;j++); } /************************************************ * 图形数据编码 *************************************************/ unsigned char code pic1[]= //Maplead board { Maplead MCU Development Board http://shop63914145.taobao.com 92 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x01,0xF0,0x03, 0xC0,0x1F,0xE0,0x0F,0xE0,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0x03, 0xC0,0x07,0xE0,0x0F,0x80,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0x03, 0xC0,0x03,0xF0,0x0F,0x80,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0x03, 0xC0,0x02,0xF0,0x17,0x80,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0x03, 0xC0,0x02,0xF0,0x17,0x80,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xF0,0x03, 0xC0,0x02,0x78,0x27,0x80,0xFC,0x1F,0x3C,0x0F,0x01,0xF0,0x0F,0xC0,0x3F,0xF0,0x03, 0xC0,0x02,0x78,0x27,0x83,0xCE,0x0F,0xCE,0x0F,0x07,0x3C,0x3C,0xE0,0x71,0xF0,0x03, 0xC0,0x02,0x7C,0x27,0x83,0xCF,0x0F,0x0F,0x0F,0x0E,0x1C,0x3C,0xF0,0xF0,0xF0,0x03, 0xC0,0x02,0x3C,0x47,0x83,0xCF,0x0F,0x07,0x8F,0x0E,0x1E,0x3C,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x3C,0x47,0x80,0x1F,0x0F,0x07,0x8F,0x1E,0x1E,0x01,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x3E,0x87,0x80,0xEF,0x0F,0x07,0x8F,0x1F,0xFE,0x0E,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x1E,0x87,0x83,0xCF,0x0F,0x07,0x8F,0x1E,0x00,0x3C,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x1E,0x87,0x87,0x8F,0x0F,0x07,0x8F,0x1E,0x00,0x78,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x0F,0x07,0x87,0x8F,0x0F,0x07,0x8F,0x1E,0x02,0x78,0xF1,0xE0,0xF0,0x03, 0xC0,0x02,0x0F,0x07,0x87,0x8F,0x0F,0x0F,0x0F,0x0F,0x04,0x78,0xF0,0xF0,0xF0,0x03, 0xC0,0x07,0x0E,0x07,0x87,0x9F,0x0F,0x8E,0x0F,0x07,0x8C,0x79,0xF0,0x71,0xF0,0x03, 0xC0,0x1F,0xC6,0x1F,0xE3,0xE7,0x8F,0x7C,0x1F,0x81,0xF0,0x3E,0x78,0x3E,0xF8,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, Maplead MCU Development Board http://shop63914145.taobao.com 93 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE3, 0xC3,0xE0,0x00,0x00,0x00,0x1E,0x0F,0x0F,0xDE,0x38,0x3F,0x80,0x00,0x00,0x00,0x63, 0xC6,0x30,0x00,0x00,0x00,0x0E,0x0E,0x30,0xCC,0x10,0x18,0xC0,0x00,0x00,0x00,0x63, 0xC6,0x30,0xF0,0x7E,0x18,0x0B,0x16,0x30,0x4C,0x10,0x18,0xC0,0x00,0x00,0x00,0x63, 0xC6,0x31,0x98,0x7E,0x78,0x0B,0x16,0x60,0x0C,0x10,0x18,0xC3,0xC3,0xC7,0x73,0xE3, 0xC3,0xE3,0x0C,0x40,0x18,0x0B,0x16,0x60,0x0C,0x10,0x1F,0x86,0x62,0x63,0xB6,0x63, 0xC6,0x33,0x0C,0x40,0x18,0x09,0xA6,0x60,0x0C,0x10,0x18,0xCC,0x30,0x63,0x0C,0x63, 0xC6,0x33,0x0C,0x7C,0x18,0x09,0xA6,0x60,0x0C,0x10,0x18,0x6C,0x33,0xE3,0x0C,0x63, 0xC6,0x33,0x0C,0x46,0x18,0x08,0xC6,0x30,0x4C,0x10,0x18,0x6C,0x36,0x63,0x0C,0x63, 0xC6,0x31,0x98,0x06,0x18,0x08,0xC6,0x30,0x86,0x20,0x18,0x66,0x66,0x63,0x06,0x63, 0xC3,0xE0,0xF0,0x06,0x7E,0x1C,0xCF,0x0F,0x03,0xC0,0x3F,0xC3,0xC3,0xF7,0x83,0xF3, 0xC0,0x00,0x00,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; unsigned char code pic2[]= //框框内的数字,字母,大写字母 { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x40,0x0F,0x00,0x3C,0x00,0x18,0x03,0xF0,0x01,0xC0,0x7F,0x00,0xF8,0x03,0xC7, Maplead MCU Development Board http://shop63914145.taobao.com 94 0xE3,0xC0,0x1F,0x80,0x7E,0x00,0x38,0x07,0xE0,0x07,0x00,0xFF,0x03,0x8C,0x06,0xE7, 0xE7,0xC0,0x33,0x80,0x8E,0x00,0x38,0x04,0x00,0x0C,0x00,0x82,0x03,0x8C,0x0E,0x77, 0xE1,0xC0,0x03,0x80,0x0C,0x00,0x78,0x07,0x80,0x1C,0x00,0x02,0x03,0xCC,0x0E,0x77, 0xE1,0xC0,0x03,0x80,0x18,0x00,0xB8,0x0F,0xE0,0x1F,0x00,0x02,0x01,0xF8,0x0E,0x77, 0xE1,0xC0,0x03,0x00,0x3C,0x01,0x38,0x0F,0xE0,0x3B,0x80,0x04,0x00,0xF0,0x0E,0x77, 0xE1,0xC0,0x07,0x00,0x1E,0x02,0x38,0x00,0xF0,0x39,0xC0,0x04,0x00,0xF8,0x07,0x77, 0xE1,0xC0,0x06,0x00,0x0F,0x03,0xFC,0x00,0x30,0x39,0xC0,0x08,0x01,0x3C,0x03,0xE7, 0xE1,0xC0,0x0C,0x00,0x07,0x03,0xFC,0x00,0x10,0x39,0xC0,0x08,0x03,0x1C,0x00,0xE7, 0xE1,0xC0,0x08,0x40,0xC7,0x00,0x38,0x0C,0x10,0x39,0xC0,0x08,0x03,0x1C,0x00,0xC7, 0xE1,0xC0,0x1F,0x80,0xE6,0x00,0x38,0x0F,0x20,0x1D,0x80,0x10,0x03,0x18,0x03,0x87, 0xE7,0xF0,0x3F,0x80,0x78,0x00,0x38,0x07,0xC0,0x0F,0x00,0x10,0x01,0xF0,0x0E,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x0F,0x00,0x00,0x00,0x07,0x80,0x00,0x01,0xE0,0x00,0x07,0x80,0x07,0x07, 0xE0,0x00,0x07,0x00,0x00,0x00,0x03,0x80,0x00,0x07,0x60,0x00,0x03,0x80,0x07,0x07, 0xE0,0x00,0x07,0x00,0x00,0x00,0x03,0x80,0x00,0x07,0x60,0x00,0x03,0x80,0x07,0x07, 0xE0,0x00,0x07,0x00,0x00,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x03,0x80,0x00,0x07, 0xE0,0xF8,0x07,0x60,0x03,0xC0,0x1B,0x80,0x38,0x0F,0x80,0x7F,0x03,0xB8,0x0F,0x07, 0xE1,0x9C,0x07,0xB0,0x06,0x60,0x37,0x80,0x6C,0x07,0x00,0xEC,0x03,0xDC,0x07,0x07, 0xE1,0x9C,0x07,0x38,0x0E,0x60,0x73,0x80,0xEE,0x07,0x00,0xEE,0x03,0x9C,0x07,0x07, 0xE0,0x3C,0x07,0x38,0x0E,0x00,0x73,0x80,0xFE,0x07,0x00,0xEE,0x03,0x9C,0x07,0x07, 0xE0,0xDC,0x07,0x38,0x0E,0x00,0x73,0x80,0xE0,0x07,0x00,0xEC,0x03,0x9C,0x07,0x07, 0xE1,0xDC,0x07,0x38,0x0E,0x00,0x73,0x80,0xE0,0x07,0x00,0x78,0x03,0x9C,0x07,0x07, 0xE1,0xDC,0x07,0x30,0x07,0x20,0x37,0xC0,0x72,0x07,0x00,0x40,0x03,0x9C,0x07,0x07, 0xE0,0xEE,0x04,0xE0,0x03,0xC0,0x1B,0x00,0x3C,0x0F,0x80,0xFE,0x07,0xDE,0x0F,0x87, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x10,0x01,0xFF,0x80,0x07,0x90,0x3F,0xC0,0x0F,0xFC,0x0F,0xFC,0x00,0xF2,0x07, 0xE0,0x18,0x00,0x73,0xC0,0x1C,0x70,0x0E,0x30,0x03,0x8C,0x03,0x8C,0x03,0x8E,0x07, 0xE0,0x38,0x00,0x71,0xC0,0x38,0x30,0x0E,0x38,0x03,0x84,0x03,0x84,0x07,0x06,0x07, Maplead MCU Development Board http://shop63914145.taobao.com 95 0xE0,0x3C,0x00,0x71,0xC0,0x30,0x10,0x0E,0x1C,0x03,0x90,0x03,0x90,0x06,0x02,0x07, 0xE0,0x5C,0x00,0x73,0x80,0x70,0x00,0x0E,0x1C,0x03,0x90,0x03,0x90,0x0E,0x00,0x07, 0xE0,0x5C,0x00,0x7F,0x00,0x70,0x00,0x0E,0x1C,0x03,0xF0,0x03,0xF0,0x0E,0x00,0x07, 0xE0,0x8E,0x00,0x73,0x80,0x70,0x00,0x0E,0x1C,0x03,0x90,0x03,0x90,0x0E,0x00,0x07, 0xE0,0x8E,0x00,0x71,0xC0,0x70,0x00,0x0E,0x1C,0x03,0x90,0x03,0x90,0x0E,0x3F,0x87, 0xE0,0xFF,0x00,0x71,0xC0,0x70,0x00,0x0E,0x1C,0x03,0x84,0x03,0x80,0x06,0x0E,0x07, 0xE1,0x07,0x00,0x71,0xC0,0x38,0x10,0x0E,0x38,0x03,0x84,0x03,0x80,0x07,0x0E,0x07, 0xE1,0x07,0x80,0x73,0x80,0x1C,0x20,0x0E,0x30,0x03,0x8C,0x03,0x80,0x03,0x8E,0x07, 0xE7,0x8F,0xC1,0xFF,0x00,0x07,0xC0,0x3F,0xC0,0x0F,0xFC,0x0F,0xE0,0x00,0xF8,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; unsigned char code pic3[]= //自行车 { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x07,0xFF,0x00,0x07,0xFF,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x0F,0xFF,0x80,0x03,0xFF,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x07,0x80,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x01,0xC0,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x07, Maplead MCU Development Board http://shop63914145.taobao.com 96 0xE0,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x03,0xF8,0x00,0x00,0x07,0xF0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x03,0xF8,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x07,0xBC,0x00,0x00,0x0F,0x78,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x0F,0x1C,0x00,0x00,0x1E,0x78,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x0F,0x1E,0x00,0x00,0x3C,0x3C,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x1E,0x0F,0x00,0x00,0x78,0x3C,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x01,0xFF,0x1C,0x0F,0x00,0x00,0xF8,0x1F,0xFE,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x0F,0xFF,0xFC,0x07,0x80,0x01,0xF0,0x1F,0xFF,0xC0,0x00,0x00,0x07, 0xE0,0x00,0x00,0x1F,0xFF,0xF8,0x07,0x80,0x01,0xE0,0x3F,0xFF,0xF0,0x00,0x00,0x07, 0xE0,0x00,0x00,0x7F,0x00,0xFC,0x03,0xC0,0x03,0xC0,0xFF,0x03,0xF8,0x00,0x00,0x07, 0xE0,0x00,0x00,0xFC,0x00,0xFE,0x01,0xC0,0x07,0x81,0xFF,0x00,0x7C,0x00,0x00,0x07, 0xE0,0x00,0x01,0xF0,0x00,0xEF,0x01,0xE0,0x0F,0x03,0xE7,0x00,0x3E,0x00,0x00,0x07, 0xE0,0x00,0x01,0xE0,0x01,0xE7,0x80,0xF3,0xDF,0x07,0xC7,0x80,0x0F,0x00,0x00,0x07, 0xE0,0x00,0x03,0xC0,0x03,0xC7,0xC0,0xF3,0xDE,0x07,0x83,0x80,0x0F,0x00,0x00,0x07, 0xE0,0x00,0x07,0x80,0x03,0xC3,0xC0,0x7A,0x3C,0x07,0x03,0xC0,0x07,0x80,0x00,0x07, 0xE0,0x00,0x07,0x80,0x07,0x81,0xC0,0x3A,0x78,0x0F,0x01,0xC0,0x03,0x80,0x00,0x07, 0xE0,0x00,0x07,0x00,0x07,0x01,0xE0,0x3E,0xF0,0x0E,0x01,0xE0,0x03,0xC0,0x00,0x07, 0xE0,0x00,0x07,0x00,0x0F,0x00,0xE0,0x1F,0xF0,0x0E,0x01,0xE0,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x0F,0x00,0x1E,0x00,0xE0,0x1F,0xE0,0x1E,0x00,0xE0,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x0E,0x00,0x1F,0xFF,0xFF,0xFF,0xC0,0x1C,0x00,0xF0,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x0E,0x00,0x3F,0xFF,0xFF,0xFF,0x80,0x1C,0x00,0x70,0x01,0xE0,0x00,0x07, 0xE0,0x00,0x0E,0x00,0x3F,0xFF,0xFF,0xFF,0x00,0x1C,0x00,0x70,0x01,0xE0,0x00,0x07, 0xE0,0x00,0x0E,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x1C,0x00,0x20,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x0F,0x00,0x00,0x00,0xE0,0x02,0x00,0x1E,0x00,0x00,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x0F,0x00,0x00,0x01,0xE0,0x02,0x00,0x1E,0x00,0x00,0x01,0xC0,0x00,0x07, 0xE0,0x00,0x07,0x00,0x00,0x01,0xE0,0x02,0x00,0x0E,0x00,0x00,0x03,0xC0,0x00,0x07, 0xE0,0x00,0x07,0x80,0x00,0x03,0xC0,0x02,0x00,0x0E,0x00,0x00,0x03,0x80,0x00,0x07, 0xE0,0x00,0x07,0x80,0x00,0x03,0xC0,0x02,0x00,0x0F,0x00,0x00,0x07,0x80,0x00,0x07, 0xE0,0x00,0x03,0xC0,0x00,0x07,0xC0,0x1E,0x00,0x07,0x80,0x00,0x0F,0x00,0x00,0x07, 0xE0,0x00,0x01,0xE0,0x00,0x07,0x80,0x1E,0x00,0x03,0xC0,0x00,0x0F,0x00,0x00,0x07, 0xE0,0x00,0x01,0xF0,0x00,0x1F,0x00,0x00,0x00,0x03,0xE0,0x00,0x3E,0x00,0x00,0x07, 0xE0,0x00,0x00,0xFC,0x00,0x7E,0x00,0x00,0x00,0x01,0xF0,0x00,0x7C,0x00,0x00,0x07, 0xE0,0x00,0x00,0x7F,0x03,0xFC,0x00,0x00,0x00,0x00,0xFE,0x01,0xF8,0x00,0x00,0x07, 0xE0,0x00,0x00,0x1F,0xFF,0xF8,0x00,0x00,0x00,0x00,0x3F,0xFF,0xF0,0x00,0x00,0x07, 0xE0,0x00,0x00,0x0F,0xFF,0xE0,0x00,0x00,0x00,0x00,0x1F,0xFF,0xC0,0x00,0x00,0x07, Maplead MCU Development Board http://shop63914145.taobao.com 97 0xE0,0x00,0x00,0x01,0xFF,0x80,0x00,0x00,0x00,0x00,0x03,0xFF,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; unsigned char code pic4[]= //两个人+地球标志 { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x00,0x07, 0xE0,0x00,0x00,0x1F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x07, 0xE0,0x00,0x00,0x7D,0x8C,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF0,0x00,0x07, 0xE0,0x00,0x00,0xF3,0x0C,0x63,0xC0,0x00,0x00,0x00,0x00,0x00,0x1F,0xF0,0x00,0x07, 0xE0,0x00,0x03,0xC7,0x0C,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x07, 0xE0,0x00,0x07,0x06,0x0C,0x38,0x78,0x00,0x00,0x00,0x0F,0x80,0x07,0xE0,0x00,0x07, 0xE0,0x00,0x1E,0x0E,0x0C,0x18,0x1C,0x00,0x00,0x00,0x1F,0xC0,0x00,0x00,0x00,0x07, 0xE0,0x00,0x1E,0x0C,0x0C,0x1C,0x1E,0x00,0x00,0x00,0x1F,0xC0,0x00,0xFE,0x00,0x07, 0xE0,0x00,0x3F,0x1C,0x0C,0x0C,0x7E,0x00,0x00,0x00,0x1F,0xC0,0x01,0xFF,0x80,0x07, 0xE0,0x00,0x73,0xD8,0x0C,0x0F,0xE3,0x00,0x00,0x00,0x0F,0x80,0x03,0xFF,0xE0,0x07, 0xE0,0x00,0x60,0xF8,0x0C,0x07,0x83,0x80,0x00,0x00,0x00,0x00,0x03,0xFF,0xF0,0x07, 0xE0,0x00,0xE0,0x3F,0x8C,0xFF,0x01,0x80,0x00,0x00,0x0F,0xE0,0x07,0xFF,0xF0,0x07, 0xE0,0x01,0xC0,0x37,0xFF,0xF3,0x00,0xC0,0x00,0x00,0x1F,0xF0,0x0F,0xFF,0xF8,0x07, 0xE0,0x01,0x80,0x70,0x7F,0x03,0x00,0xE0,0x00,0x00,0x1F,0xF8,0x0F,0xFF,0xFC,0x07, Maplead MCU Development Board http://shop63914145.taobao.com 98 0xE0,0x03,0x80,0x60,0x0C,0x03,0x00,0x60,0x00,0x00,0x3F,0xF8,0x1F,0xFF,0xFE,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x03,0x00,0x60,0x00,0x00,0x3F,0xFC,0x7F,0xFF,0x9F,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x01,0x80,0x70,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0x9F,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x01,0x80,0x70,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0x9E,0x07, 0xE0,0x03,0x00,0xC0,0x0C,0x01,0x80,0x30,0x00,0x00,0xFF,0xFF,0xF3,0xFF,0xDF,0x87, 0xE0,0x06,0x00,0xC0,0x0C,0x01,0x80,0x30,0x00,0x01,0xFF,0xFF,0x81,0xFF,0xFF,0x87, 0xE0,0x06,0x00,0xC0,0x0C,0x00,0xC0,0x38,0x00,0x07,0xFF,0xFE,0x01,0xFF,0xFF,0x87, 0xE0,0x06,0x00,0xC0,0x0C,0x00,0xC0,0x38,0x00,0x0F,0xDF,0xFF,0xC1,0xFF,0xFF,0xC7, 0xE0,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x3F,0x1F,0xFF,0xC1,0xFF,0xFF,0xC7, 0xE0,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x7E,0x1F,0xFF,0xC0,0xFF,0xFF,0xC7, 0xE0,0x06,0x00,0xC0,0x0C,0x00,0xC0,0x38,0x00,0x38,0x3F,0xFF,0xC1,0xFF,0xFE,0x07, 0xE0,0x06,0x00,0xC0,0x0C,0x00,0xC0,0x38,0x00,0x00,0x3F,0xF8,0x01,0xFF,0xC0,0x07, 0xE0,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x30,0x00,0x00,0x3F,0xF8,0x03,0xFF,0xC0,0x07, 0xE0,0x03,0x00,0xC0,0x0C,0x01,0x80,0x30,0x00,0x00,0x7F,0xFC,0x03,0xFF,0xC0,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x00,0x00,0x7F,0xFC,0x07,0xFF,0xC0,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x01,0x80,0x70,0x00,0x00,0x7F,0xFC,0x07,0xFF,0x80,0x07, 0xE0,0x03,0x00,0x60,0x0C,0x03,0x80,0x60,0x00,0x00,0xFF,0xFE,0x0F,0xEF,0x80,0x07, 0xE0,0x03,0x80,0x60,0x0C,0x03,0x00,0x60,0x00,0x00,0xFF,0xFE,0x0F,0xCF,0x80,0x07, 0xE0,0x01,0x80,0x70,0x7F,0x03,0x00,0xE0,0x00,0x01,0xFF,0xFE,0x1F,0xCF,0x80,0x07, 0xE0,0x01,0xC0,0x37,0xFF,0xF3,0x00,0xC0,0x00,0x00,0x7C,0xF0,0x1F,0x8F,0x80,0x07, 0xE0,0x00,0xC0,0x3F,0xCC,0xFF,0x01,0x80,0x00,0x00,0xF9,0xF0,0x1F,0x0F,0xC0,0x07, 0xE0,0x00,0x60,0xF8,0x0C,0x07,0x83,0x80,0x00,0x00,0xF1,0xF0,0x1F,0x0F,0xC0,0x07, 0xE0,0x00,0x73,0xD8,0x0C,0x0F,0xE3,0x00,0x00,0x00,0xF0,0xF0,0x1F,0x07,0xE0,0x07, 0xE0,0x00,0x3F,0x9C,0x0C,0x0C,0x7E,0x00,0x00,0x00,0xF0,0xF8,0x1F,0x03,0xF0,0x07, 0xE0,0x00,0x1E,0x0C,0x0C,0x1C,0x1E,0x00,0x00,0x00,0xF0,0x78,0x1F,0x03,0xF0,0x07, 0xE0,0x00,0x1E,0x0E,0x0C,0x18,0x1C,0x00,0x00,0x00,0xF0,0x7C,0x1F,0x01,0xF8,0x07, 0xE0,0x00,0x07,0x06,0x0C,0x30,0x78,0x00,0x00,0x00,0xF8,0x3C,0x1F,0x00,0xF8,0x07, 0xE0,0x00,0x03,0x83,0x0C,0x30,0xE0,0x00,0x00,0x00,0x78,0x3E,0x1F,0x00,0xFC,0x07, 0xE0,0x00,0x00,0xF3,0x0C,0x63,0xC0,0x00,0x00,0x00,0x78,0x1E,0x3F,0x00,0x7C,0x07, 0xE0,0x00,0x00,0x7D,0x8C,0xFF,0x00,0x00,0x00,0x00,0x78,0x1F,0x3F,0x00,0x7E,0x07, 0xE0,0x00,0x00,0x1F,0xEF,0xFE,0x00,0x00,0x00,0x00,0x78,0x0E,0x3F,0x00,0x3E,0x07, 0xE0,0x00,0x00,0x07,0xFF,0xF0,0x00,0x00,0x00,0x00,0x78,0x00,0x3E,0x00,0x1E,0x07, 0xE0,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x18,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, Maplead MCU Development Board http://shop63914145.taobao.com 99 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; Maplead MCU Development Board http://shop63914145.taobao.com 100 15.LED 点阵 LED 点阵原理 图 15-1 LED 点阵接口原理图 由 LED 点阵接口原理图可知该点阵实质上是 8×8 个发光二极管构成的显示 阵列,由许多个发光二极管“同时”(实际上是快速点亮熄灭,利用人眼睛的视觉 暂留效应感觉上是同时发光的)发光构成某个字符或者图形。 从原理图可以得知,单片机的 P2 口驱动 LED 点阵的各个“行”,驱动的是各 个 LED 的“阴极”(负极);而 74HC573 驱动 LED 点阵的各个“列”,驱动的是各 个 LED 的“阳极”(正极)。当某个 LED 的阳极和阴极同时被驱动的时候,则这 个 LED 就会被点亮。 例如,我们要点亮第 2 行,第 1 列的 LED,我们只需要给 Q1 点一个高电平, 给 P2.0 一个低电平,则第 2 行第 1 列的 LED 就会被点亮。当给 Q1 点一个低电 平,或者给 P2.0 一个高电平的时候,该 LED 就会熄灭。 其它各行各列的 LED 驱动方式皆同此理。 LED 点阵的扫描方式 (1)行扫描方式 行扫描方式是指,每次驱动点亮的 LED 是以行为单位,P2 口先给出某个行 中 8 个 LED 的亮或灭(低电平亮,高电平灭),然后 74HC573 瞬时只给出一个 高电平,则给出高电平的某行就会被驱动。 Maplead MCU Development Board http://shop63914145.taobao.com 101 图 15-2 LED 点阵字符 例如,图 14-2 给出一个 8×8 点阵的字符,如果此字符采用行扫描的方式显 示,则在瞬时的第 1 个时刻,单片机只驱动字符的第 1 行(P2 口值为 11100011B), 瞬时的第 2 时刻只驱动字符的第 2 行( P2 口值为 11011101B),下面的以此类推, 共切换 8 次驱动 8 行,第 8 行驱动完毕后第 1 帧显示完毕,又切换到第 1 行,如 此循环往复。由于单片机驱动每 1 行的切换速度很快,人们就会感觉显示此字符 的每一个点都是同时显示的。 (2)列扫描方式 与行扫描方式类似,只不过每次点亮的是以列为单位。 (3)点扫描方式 每次只点亮 1 个点。从第 1 行的第 1 列开始显示,点亮顺序分别为,第 1 行第 1 列,第 1 行第 2 列,第 1 行第 3 列……第 8 行第 8 列。最后一个点显示完 成后又回到第 1 点,重复刚才的显示顺序。 点扫描的方式因为每次只扫描一个点,8×8 的点阵扫描完一帧需要扫描 64 次,因而其扫描效率很低,为行扫描或者列扫描速度的 1/8。 0~9LED 数字点阵及其编码 0~9 每个数字在 8×8LED 点阵上需要点亮的点如图 14-3 所示(由于本作者 手拙,有兴趣的读者可以自己描绘每一个点,相信你会做得更好)。 我们把每一个需要点亮的点用红点来表示,没有红点的地方代表该点的 LED 不被点亮。 例如,数字“3”的第一行,需要点亮的点为第 4,5,6 个,其它点的 LED 都熄 灭。因为 P2 口驱动的是每个 LED 的阴极,端口输出“1”表示该点的 LED 熄灭, Maplead MCU Development Board http://shop63914145.taobao.com 102 “0”表示该点的 LED 点亮。其对应的 P2 口的二进制数为 11100011B,16 图 15-3 0~9 数字点阵及其编码 0x1C 0x22 0x22 0x22 0x22 0x22 0x22 0x1C 0x08 0x18 0x08 0x08 0x08 0x08 0x08 0x1C 0x02 0x02 0x1C 0x04 0x02 0x22 0x1C 0x1E 0x20 0x20 0x20 0x1C 0x02 0x02 0x3C 0x3E 0x22 0x04 0x04 0x08 0x08 0x08 0x08 0x1C 0x22 0x22 0x22 0x1E 0x02 0x02 0x3C 0x1C 0x22 0x22 0x04 0x08 0x10 0x22 0x3E 0x04 0x14 0x14 0x24 0x24 0x3E 0x04 0x04 0x0C 0x10 0x20 0x20 0x1C 0x22 0x22 0x1C 0x1C 0x22 0x22 0x1C 0x22 0x22 0x22 0x1C Maplead MCU Development Board http://shop63914145.taobao.com 103 进制编码为 0x1C。以此类推第 2 行 16 进制编码为 0x02,第 3 行为 0x02,第 4 行为 0x01C,第 5 行为 0x04,第 6 行为 0x02,第 7 行为 0x22,第 8 行为 0x1C。 LED 点阵数字显示演示程序 在本例程中,我们不采用整行扫描的方式,尽管这种方式比单点扫描的效率 高。因为 74HC573 以及单片机的电流驱动能力有限,当整行显示某个字符的时 候,有的行点亮的 LED 数量多电流消耗大,而有的行点亮的 LED 数量少电流消 耗小,这就造成了各行 LED 显示的亮度不均匀,点亮 LED 数量少的行总比点亮 LED 数量多的行亮度高。而采用点扫描的方式,因为每次只点亮一个 LED,电 流相同,所以亮度总是均匀的。在现实应用中(如 LED 点阵屏),会有相应的功 率驱动电路负责点亮 LED,因为电路的电流驱动能力强,所以进行行扫描的时 候就不存在各行显示亮度不均匀的情况了。 LED 点阵实验连接图 图 15-4 LED 点阵实验连接(点阵有字一面向下) LED点阵安装时,每个排针都要对齐点阵插座,不可错位。 例程 15-1 LED 点阵数字显示 /****************************************************************************** (1)晶振 12Mhz 调试通过。 (2)数字显示采用点扫描的形式。因为用行扫描其亮度明显不均衡(每行点亮的 LED 数量 不同,而 74HC573 的电流驱动能力又不足,所以造成每行的亮度不均衡。点亮 LED 数量少的行亮度高,点亮 LED 数量多的行亮度低)。 (3)显示扫描顺序:从上到下;从左到右。 (4)由于 74HC573 驱动电流较小(所以没有用限流电阻),所以显示的亮度稍暗。 (5)电路图见图 15-1。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include Maplead MCU Development Board http://shop63914145.taobao.com 104 void LED_Matrix_Disp(unsigned char); //LED 显示函数声明 void main(void) { unsigned char i,j; while(1) { for(i=0;i<10;i++) //显示 0~9 数字 { for(j=0;j<50;j++) //每个数字显示 50 次 LED_Matrix_Disp(i); } } } /****************************************************************************** * LED点阵显示函数 ******************************************************************************/ void LED_Matrix_Disp(unsigned char Data) { unsigned char code Number[10][8]={ { 0x1C,0x22,0x22,0x22,0x22,0x22,0x22,0x1C}, //数字 0 编码 {0x08,0x18,0x08,0x08,0x08,0x08,0x08,0x3E}, //数字 1 编码 {0x1C,0x22,0x22,0x04,0x08,0x10,0x22,0x3E}, //数字 2 编码 {0x1C,0x02,0x02,0x1C,0x04,0x02,0x22,0x1C}, //数字 3 编码 {0x04,0x14,0x14,0x24,0x24,0x3E,0x04,0x04}, //数字 4 编码 {0x1E,0x20,0x20,0x20,0x1C,0x02,0x02,0x3C}, //数字 5 编码 {0x0C,0x10,0x20,0x20,0x1C,0x22,0x22,0x1C}, //数字 6 编码 {0x3E,0x22,0x04,0x04,0x08,0x08,0x08,0x08}, //数字 7 编码 {0x1C,0x22,0x22,0x1C,0x22,0x22,0x22,0x1C}, //数字 8 编码 {0x1C,0x22,0x22,0x22,0x1E,0x02,0x02,0x3C} }; //数字 9 编码 unsigned char i,j,k,Val; unsigned char X_Row, Y_Row; Y_Row=0x01; //初始化 Y 行显示(从上面的第一行开始显示) for(i=0;i<8;i++) { Val=Number[Data][i]; //取编码,每个数字有 8 字节编码,所以共取 8 次 P0 =Y_Row; //瞬间只显示一行 X_Row=0x01; //初始化 X 行显示(从左边的第一个点开始显示) for(j=0;j<8;j++) //每行 8 个点,共显示 8 次 { Val <<=1; //将数字码的最高位移入 CY 位 if(CY) //如果此点为亮 P2=~X_Row; //点亮此点 else //如果是暗 P2=0xFF; //关闭显示 X_Row <<=1; //准备显示本行中的下一个点 for(k=0;k<100;k++); } Y_Row <<=1; //切换到下一行显示 } } Maplead MCU Development Board http://shop63914145.taobao.com 105 16.PS2 接口 PS2 接口定义: 图 16-1 PS2 插座 PS2 发送每帧的数据是 11 位。PS2 帧的第一位是起始位,为 0,然后是 8 位 数据位(8 位数据位的低位在前,高位在后),发送键盘扫描码的一个字节(扫 描码为 1-4 个字节),然后是奇偶校验位,最后是停止位,为 1。这些是在数据线 (即 1 号引脚线)上发送的。无键按下时,数据线和时钟线都保持为 1。当有键 按下时,PS2 设备首先检测时钟线与数据线是否为高,为高则发送数据,CLOCK 送出脉冲,同时数据线送出数据。主机始终在时钟脉冲的下降沿对数据线采样获 得数据。 表 16-1 PS2 数据传输格式 DB1 起始位,为 0 DB2~DB9 数据位 DB10 奇偶校验位,奇校验 DB11 停止位,为 1 (DB12) 应答,用于主机对设备通信中 PS2 键盘扫描码 键盘扫描码包括通码和断码,当键按下时发送通码,抬起时发送断码。更详 细的内容可参考所附的《PS2 接口协议》。 通电时键盘会自检,此时键盘上三个灯全亮,自检完成后熄灭,若通过,则 向主机发送十六进制字符 0xAA。 图 16-2 PS2 接口数据发送时序图 1 2 3 4 5 6 DATA NC GND VCC CLK NC Maplead MCU Development Board http://shop63914145.taobao.com 106 表 16-2 键盘通码/断码表 KEY 通码 断码 KEY 通码 断码 KEY 通码 断码 A 1C F01C 9 46 F046 [ 54 F054 B 32 F032 ` 0E F00E INSERT E070 E0 F070 C 21 F021 - 4E F04E HOME E06C E0 F06C D 23 F023 = 55 F055 PG UP E07D E0 F07D E 24 F024 \ 5D F05D DEL E071 E0 F071 F 2B F02B BKSP 66 F066 END E069 E0 F069 G 34 F034 SPACE 29 F029 PG DN E07A E0 F07A H 33 F033 TAB 0D F00D ↑ E075 E0 F075 I 43 F043 CAPS 58 F058 ← E06B E0 F06B J 3B F03B L SHFT 12 F012 ↓ E072 E0 F072 K 42 F042 L CTRL 14 F014 → E074 E0 F074 L 4B F04B L GUI E01F E0 F01F NUM 77 F077 M 3A F03A L ALT 11 F011 KP/ E04A E0 F04A N 31 F031 R SHFT 59 F059 KP* 7C F07C O 44 F044 R CTRL E014 E0 F014 KP- 7B F07B P 4D F04D R GUI E027 E0 F027 KP+ 79 F079 Q 15 F015 R ALT E011 E0 F011 KP EN E05A E0 F05A R 2D F02D APPS E02F E0 F02F KP 71 F071 S 1B F01B ENTER 5A F05A KP 0 70 F070 T 2C F02C ESC 76 F076 KP 1 69 F069 U 3C F03C F1 05 F005 KP 2 72 F072 V 2A F02A F2 06 F006 KP 3 7A F07A W 1D F01D F3 04 F004 KP 4 6B F06B X 22 F022 F4 0C F00C KP 5 73 F073 Y 35 F035 F5 03 F003 KP 6 74 F074 Z 1A F01A F6 0B F00B KP 7 6C F06C 0 45 F045 F7 83 F083 KP 8 75 F075 1 16 F016 F8 0A F00A KP 9 7D F07D 2 1E F01E F9 01 F001 ] 58 F058 3 26 F026 F10 09 F009 ; 4C F04C 4 25 F025 F11 78 F078 ‘ 52 F052 Maplead MCU Development Board http://shop63914145.taobao.com 107 5 2E F02E F12 07 F007 , 41 F041 6 36 F036 PRNT SCRN E012 E07C E0F0 7CE0 F012 . 49 F049 7 3D F03D SCROLL 7E F07E / 4A F04A 8 3E F03E PAUSE E114 77 E1F0 14 F077 -NONE PS2 键盘解码演示程序 图 16-3 开发板 PS2 接口电路原理图 根据以上 PS2 数据传输规则及图 16-3,我们设计一个对 PS2 键盘进行解码 的程序。其思路为: 1. 开单片机外部中断 0,并定义触发条件为负跳变触发。 2. 单片机 P1.5 口作为输入口,接收 PS2 键盘发来的数据。初始化时置该端 口为高电平,随时准备读取数据。 3. 当单片机外部中断 0 被触发时,说明 PS2 键盘向单片机发送了数据,并 且已经准备好数据在数据线上。 4. 读取数据,并且将其存放于某个变量中。 Maplead MCU Development Board http://shop63914145.taobao.com 108 开发板 PS2 接口实物图 图 16-4 开发板 PS2 接口实物图 例程 16-1 PS2 键盘解码程序 /****************************************************************************** (1)晶振 12Mhz 调试通过。 (2)上电后请先复位或重启一下单片机。 (3)只接收 1 字节的数据并显示在 LED 数码管上(多字节不考虑,没有通信错误处理能力)。 (4)继续扩展完善功能! (5)电路图见图 16-3。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include void Display(unsigned char); sbit D_IO = P1^5; //定义数据口 unsigned char Key_Data; //接收到的数据 bit Flag=1; //一个字节接收完毕标志(1:完毕;0:未完毕) void main(void) { IT0=1; //外部中断 0,下降沿触发 EX0=1; //使能外部中断 0 EA =1; //使能总中断 D_IO=1; while(1) { if(Flag && (Key_Data!=0xF0)) //断码的 F0 不显示,避免数码管闪烁 Display(Key_Data); Maplead MCU Development Board http://shop63914145.taobao.com 109 } } /****************************************************************************** 外部中断 0 处理函数 (1)外部中断 0 为下降沿触发,当 PS2 键盘发送数据时,在每次时钟的下降沿采集数据信号, 并将值保存在全局变量 Key_Data 中。 ******************************************************************************/ void INT0_ISR() interrupt 0 using 1 { static unsigned char i=0; i++; Flag=0; //清零接收完毕标志 if((i>1) && (i<10)) //只取 8 位数据值,起始位、校验位、结束位丢弃 { if(D_IO) //如果数据位为"1" { Key_Data>>=1; //右移 1 位 Key_Data|=0x80; //Key_Data 的最高位置 1 } else //如果数据位为 0 { Key_Data>>=1; //右移一位,最高位自动补 0 } } if(i>=11) //如果一个数据帧发送完毕 { i =0; //清零位计数 Flag=1; //置位接收完毕标志 } } Maplead MCU Development Board http://shop63914145.taobao.com 110 17.DS1302 实时时钟 DS1302 实时时钟芯片 DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/ 日历和 31 字节静态 RAM,通过简单的串行接口与单片机进行通信。 „ 实时时钟/日历电路包含 2100 年以前的秒、分、时、日、月、周、年的信息, 能够自动进行闰年补偿。 „ 31×8 位 RAM,便于中间结果暂存。 „ 使用串口通信方式,简单的 3 线接口,占用较少的端口资源。 „ 2.0V~5.5V 宽电压运行范围。 „ 2.0V 时,消耗电流量小于 300nA。 „ 可采用单字节模式或多字节模式(突发模式)对实时时钟或 RAM 进行读写 操作。 „ TTL 电平兼容(Vcc=5V)。 „ 可供选择的工业级温度范围,-40 ~+85℃℃。 图 17-1 DS1302 结构图 Maplead MCU Development Board http://shop63914145.taobao.com 111 图 17-2 DS1302 引脚图 表 17-1 DS1302 各引脚说明 X1,X2 32.768KHz 晶振输入脚。 GND 电源地。 RST 复位引脚。 I/O 数据输入输出口。 SCLK 串行时钟输入口。 VCC1 备用电源引脚,带有涓流充电功能。 VCC2 主电源引脚。 DS1302 的命令字结构 表 17-2 DS1302 命令字 对 DS1302 的读写必须以写入一个命令字作为开始。命令字的最高位(位 7) 必须为 1,为 0 则不能对 DS1302 进行读写操作。 命令字的次高位(位 6)为 RAM 与时钟日历寄存器选择位,当该位为 1 时, 是对 DS1302 的 31 个 RAM 进行读写,以便存储或者读取某些变量(如定时时间、 闹钟时间等);当该位为 0 时,是对 DS1302 的时钟日历寄存器进行读写,以便 设定或者获取当前日历时间。 命令字的位 5~位 1 是欲读写寄存器的地址。例如,秒寄存器的地址为 00000B,对秒寄存器进行读写所对应的命令字位 5~位 1 为 00000B。 命令字的最低位(位 0)为读写选择位。当该位为 1 时,是对地址指定的寄 存器进行读操作;当该位为 0 时,则对地址指定的寄存器进行写操作。 Maplead MCU Development Board http://shop63914145.taobao.com 112 DS1302 各寄存器的地址及数据存储结构 图 17-3 DS1302 时钟/日历寄存器的地址及数据结构 DS1302 时钟/日历寄存器的秒、分、时、日、月、周、年、控制、涓流充电、 突发模式寄存器的地址(位 1~位 5)分别为 0、1、2、3、4、5、6、7、8、31。 秒寄存器: 秒寄存器的最高位(CH 位)为时钟停止位。当该位为 1 时,DS1302 的时 钟振荡器停止运行,器件进入低功耗待命模式,器件电流消耗小于 100nA;当该 位为 0 时,DS1302 时钟振荡器开始工作,器件开始运行。上电后,该位的状态 未定义,因此上电后应该对该位进行适当的设定。 位 6~位 4 为秒的十位 BCD 码,其范围为 0~5;位 3~位 0 为秒的个位 BCD 码,其范围为 0~9。因此,秒寄存器位 6~位 0 的 BCD 码表示范围为 00~59。 Maplead MCU Development Board http://shop63914145.taobao.com 113 分寄存器: 分寄存器的最高位(位 7)为 0。 位 6~位 4 为分的十位 BCD 码,其范围为 0~5;位 3~位 0 为分的个位 BCD 码,其范围为 0~9。因此,分寄存器位 6~位 0 的 BCD 码表示范围为 00~59。 时寄存器: 时寄存器的最高位(位 7)为 12 小时/24 小时模式选择位。 当最高位为 1 时,时寄存器为 12 小时模式,此时,位 5 为 AM/PM(上午/ 下午)表示位,当位 5 为 1 时,表示现在的时间为 PM(下午)。 当最高位为 0 时,为 24 小时模式,此时,位 5 与位 4 共同表示小时十位的 BCD 码,该两位的表示范围为 0~2。 位 6 为 0。 位 3~位 0 为小时个位的 BCD 码,其表示范围为 0~9。 因此,在 12 小时模式下,时寄存器位 4~位 0 的 BCD 码表示范围为 01~12, 位 5 为 AM/PM 表示位。在 24 小时模式下,时寄存器位 5~位 0 的 BCD 码表示 范围为 00~23。 日寄存器: 日寄存器的最高位(位 7)和次高位(位 6)都为 0。 日寄存器的位 5~位 4 为日期的十位 BCD 码,其表示范围为 0~3。 日寄存器的位 3~位 0 为日期的个位 BCD 码,其表示范围为 0~9。 因此,日寄存器位 5~位 0 的 BCD 码能够表示的范围为 01~28 或 01~29 (DS1302 带有自动闰年补偿功能)或 01~30 或 01~31。 月寄存器: 月寄存器的最高位(位 7)、次高位(位 6)和第 5 位都为 0。 月寄存器的位 4 为月的十位 BCD 码,其表示范围为 0~1。 月寄存器的位 3~位 0 为月的个位 BCD 码,其表示范围为 0~9。 因此,月寄存器位 4~位 0 的 BCD 码能够表示的范围为 01~12。 Maplead MCU Development Board http://shop63914145.taobao.com 114 周寄存器: 周寄存器的位 7~位 3 都为 0。 周寄存器的位 2~位 0 为周的 BCD 码,其表示范围为 1~7,分别表示周一至 周天 7 天。 年寄存器: 年寄存器的高 4 位为年的十位的 BCD 码,其表示范围为 0~9。 年寄存器的低 4 位为年的个位的 BCD 码,其表示范围为 0~9。 因此,年寄存器 BCD 码表示的范围为 00~99,分别表示 2000 年~2099 年。 (2099 年后的事情想必对我辈来说暂时不用考虑了^_^)。 控制寄存器: 控制寄存器的最高位为写保护位(WP 位),其余位都为 0。 当 WP 位为 1 时,器件进入写保护模式,任何企图对器件的写入操作都将无 效,而只能对器件各寄存器进行读操作。当欲向器件写入数据时,需将 WP 位清 零,写入数据操作完成后再将该位置 1,以防止发生不希望的误写入动作篡改系 统时间,造成系统时间的错误。 WP 位上电后的数据不确定,因此在初始化过程中需明确指定该位的状态。 DS1302 的 RAM 寄存器 图 17-4 DS1302 的 RAM 寄存器 DS1302 拥有地址为 0~30 的 31 个 RAM 寄存器,可以使用单片机对这 31 个 RAM 单元进行读写操作。对这 31 个 RAM 单元的读写操作与对时钟寄存器的操 作类似(只是 RAM/CK 选择位为 1),先写入操作指令(包含目的操作地址), 再读/写数据。 Maplead MCU Development Board http://shop63914145.taobao.com 115 DS1302 的 31 个 RAM 单元可以用来存储中间结果等数据。因为 DS1302 有 Vcc1 备用电源,当主电源掉电后,在备用电源的作用下,DS1302 可以继续运行 而不会有数据丢失。因此,可以将一些设定参数等数据存放于这 31 个单元中以 达到长时间存储并且掉电不丢失的目的(备用电源充足的情况下作为 E2PROM 使用)。 DS1302 的涓流充电功能 图 17-5 DS1302 涓流充电控制寄存器各位对应的功能 涓流充电控制寄存器的位 7~位 4 为充电选择位(相当于开关),只有该 4 位 为 1010 时,DS1302 的涓流充电功能才能被选通。 涓流充电控制寄存器的位 3 与位 2 为二极管选择位,当此 2 位为 01 时,Vcc1 与主电源之间将被 1 只二极管联通;当此 2 位为 10 时,Vcc1 与主电源之间将被 2 只二极管联通。我们知道,硅二极管的电压降为 0.7V,因此,当连接一只二极 管后,Vcc1 端口电压为(Vcc2-0.7V);当连接两只二极管后,Vcc1 端口电压为 (Vcc2-0.7V×2)=(Vcc2-1.4V)。通过此 2 位的选择能够对电池的充电电压和电流 (配合电阻选择位)进行控制。 涓流充电控制寄存器的位 1 与位 0 为电阻选择位,电阻的选择见表 17-3。 Maplead MCU Development Board http://shop63914145.taobao.com 116 表 17-3 涓流充电控制寄存器的电阻选择 通过表 17-3 我们可以灵活地选择连接端口 Vcc1 与主电源之间的电阻的阻 值,从而配合二极管的选择对充电电压和电流进行灵活控制。 例如,系统主电源电压为 5V 时,我们想让涓流充电电压为 4.3V,充电电流 小于等于 2mA,那么我们可以设定二极管选择位为 01,选择一个二极管,压降 为 0.7V;电阻选择位为 01,对应的电阻为 2KΩ,则充电最大电流可计算为: DS1302 的数据输入输出操作 RST 与 SCLK 控制: 数据传输以 RST 为高电平作为初始条件。RST 的基本作用有两个:首先, RST 接通控制逻辑,允许数据的输入输出操作;其次,RST 是终止单字节、多 字节数据传输的手段,在数据传输过程中将 RST 拉低将终止目前的单字节、多 字节数据的传输使数据口变为高阻态。上电后,在 VCC>2.0V 之前 RST 必须等 于 0。在 RST 由低电平变为高电平之前,SCLK 必须等于 0。 数据输入: 图 17-6 数据输入时序图 数据总是从字节的最低位(bit0)开始传输。DS1302 器件在每个时钟(SCLK) 的上升沿将数据位读入移位寄存器内,8 个时钟传输 1 字节的数据。当 8 位的命 令字节传输完后,紧接着在每个时钟的上升沿将数据的每个位读入器件内。数据 传输完后,额外的 SCLK 操作将会被器件忽略。 数据输出: Maplead MCU Development Board http://shop63914145.taobao.com 117 图 17-7 数据读取时序图 当 8 位的命令字节输入完成后,数据会在接下来的 8 个时钟内由器件输出。 第 1 个数据位会在命令字节最后一个时钟的下降沿输出,此后的数据位在每个时 钟的下降沿输出。数据的输出是从最低位(bit0)开始的,最高位最后输出。 突发模式(burst mode)输入输出: 当写入时钟/RAM 的突发输入/输出命令后,器件的数据传输进入突发传输模 式。在该模式下,只要器件的 RST 脚维持为高电平,随着 SCLK 时钟的输入, 数据会从 I/O 口进行连续地输入/输出。任何时刻 RST 变为低电平都会终止突发 模式的读/写操作(例如,只希望读/写前 3 个寄存器,则在读/写完前 3 个寄存器 后将 RST 拉低,则传输终止)。该模式从寄存器第 0 地址的第 0 位开始依次进行 读/写,读/写完一个字节后地址自动加 1,进入到下一个地址的寄存器进行下一 个读/写操作。该模式由于只需要写入一次命令便可以对多个寄存器或 RAM 进行 连续读/写,而不需要每次都写入读/写寄存器的地址指令,因此在对器件寄存器 进行连续读/写的时候,能够节省单片机对器件的读/写时间。 值得注意的是:在读写时钟/日历寄存器的时候,突发模式下只能连续依次 读/写地址 0~8 的时钟/日历寄存器,对地址 9 及地址 9 以上寄存器的读/写都为无 效操作。在突发模式下读/写 RAM 寄存器的时候,只能连续依次读/写地址 0~30 的时钟/日历寄存器,对地址 31 个及地址 31 以上的寄存器的读/写都为无效操作。 在时钟/日历寄存器进行突发模式读写开始的时候,器件会将当前时间转移 到备用时钟/日历寄存器中,以防止在对时钟/日历寄存器进行读/写的过程中器件 对时钟/日历进行了更新(例如,当前时间为 21 点 11 分 59 秒,读取当前秒寄存 器的值为 59,当读取完秒寄存器的瞬间,器件对时间进行了更新,增加了 1 秒, 因此接下来读取到的分钟值将会是 12,那么此次读取的时间将会是 21 点 12 分 59 秒,这是错的。将当前寄存器中的数值转移到备用寄存器中,那么突发模式 读取备用寄存器的值将会在整个读取过程中都保持不变,都是写入突发读/写命 令瞬间的时间值,从而避免了上述读取错误情况的发生)。 Maplead MCU Development Board http://shop63914145.taobao.com 118 开发板实时时钟模块实物图片 图 17-8 开发板实时时钟模块 DS1302 演示程序 例程 17-1 DS1302 实时时钟读写 /***************************************************************************** 晶振 12Mhz 调试通过。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #define Year_R 0x8D //读年寄存器地址 #define Week_R 0x8B //读周寄存器地址 #define Month_R 0x89 //读月寄存器地址 #define Day_R 0x87 //读日寄存器地址 #define Hour_R 0x85 //读时寄存器地址 #define Min_R 0x83 //读分寄存器地址 #define Sec_R 0x81 //读秒寄存器地址 #define Bst_R 0xBF //读突发寄存器地址 #define Year_W 0x8C //写年寄存器地址 #define Week_W 0x8A //写周寄存器地址 #define Month_W 0x88 //写月寄存器地址 #define Day_W 0x86 //写日寄存器地址 #define Hour_W 0x84 //写时寄存器地址 #define Min_W 0x82 //写分寄存器地址 #define Sec_W 0x80 //写秒寄存器地址 #define Bst_W 0xBE //写突发寄存器地址 Maplead MCU Development Board http://shop63914145.taobao.com 119 #define Ctr_W 0x8E //写控制寄存器地址 sbit CLK=P2^3; sbit DIO=P2^4; sbit RST=P1^2; unsigned char code LED_Seg[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F, 0x40}; //数码管 0~9 段码,"-" unsigned char code LED_Bit[]= {0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00}; //数码管(1~8 位)位码 void delay(void); sbit K1=P3^2; void main(void) { struct TIME Time; unsigned char * tm; Time.Year =0x11; //11 年 Time.Week =0x03; //星期三 Time.Month =0x09; //9 月 Time.Day =0x14; //14 日 Time.Hour =0x00; //0 点 Time.Minute=0x53; //0 分 Time.Second=0x00; //0 秒 Time_Set(Time); while(1) { tm=Time_Read(); if(!K1) //K1按下则显示年月日 { P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[*(tm+6)&0x0F]; //年 低位 delay(); P0=0x00; P2=LED_Bit[0]; P0=LED_Seg[(*(tm+6)&0xF0)>>4]; //年 高位 delay(); P0=0x00; P2=LED_Bit[2]; P0=LED_Seg[10]; //第 3 位显示"-" delay(); P0=0x00; P2=LED_Bit[4]; P0=LED_Seg[*(tm+4)&0x0F]; //月 低位 delay(); P0=0x00; Maplead MCU Development Board http://shop63914145.taobao.com 120 P2=LED_Bit[3]; P0=LED_Seg[(*(tm+4)&0xF0)>>4]; //月 高位 delay(); P0=0x00; P2=LED_Bit[5]; P0=LED_Seg[10]; //第 6 位显示"-" delay(); P0=0x00; P2=LED_Bit[7]; P0=LED_Seg[*(tm+3)&0x0F]; //日 低位 delay(); P0=0x00; P2=LED_Bit[6]; P0=LED_Seg[(*(tm+3)&0xF0)>>4]; //日 高位 delay(); } else //K1未按下则显示时分秒 { P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[*(tm+2)&0x0F]; //时 低位 delay(); P0=0x00; P2=LED_Bit[0]; P0=LED_Seg[(*(tm+2)&0xF0)>>4]; //时 高位 delay(); P0=0x00; P2=LED_Bit[2]; P0=LED_Seg[10]; //第 3 位显示"-" delay(); P0=0x00; P2=LED_Bit[4]; P0=LED_Seg[*(tm+1)&0x0F]; //分 低位 delay(); P0=0x00; P2=LED_Bit[3]; P0=LED_Seg[(*(tm+1)&0xF0)>>4]; //分 高位 delay(); P0=0x00; P2=LED_Bit[5]; P0=LED_Seg[10]; //第 6 位显示"-" delay(); P0=0x00; P2=LED_Bit[7]; P0=LED_Seg[(*tm)&0x0F]; //秒 低位 delay(); Maplead MCU Development Board http://shop63914145.taobao.com 121 P0=0x00; P2=LED_Bit[6]; P0=LED_Seg[((*tm)&0xF0)>>4]; //秒 高位 delay(); } } } /****************************************************************************** * 延时 ******************************************************************************/ void delay(void) { unsigned char i; for(i=0;i<255;i++); } /****************************************************************************** * RST与 CLK 控制初始化 ******************************************************************************/ void DS1302_Init(void) { RST=0; CLK=0; RST=1; } /******************************************** * 字节发送 *********************************************/ void Byte_Send(unsigned char Data) { unsigned char i; for(i=0;i<8;i++) { CLK=0; DIO=(bit)(Data & 0x01); CLK=1; Data >>=1; } DIO=0; //拉低数据位(不然数据传输会出错) } /****************************************************************************** * 字节接收 ******************************************************************************/ unsigned char Byte_Rcv(void) { unsigned char i, Data; DIO=1; for(i=0;i<8;i++) { Data >>= 1; CLK=0; Maplead MCU Development Board http://shop63914145.taobao.com 122 if(DIO) Data |=0x80; CLK=1; } DIO=0; //拉低数据位(不然数据传输会出错) return Data; } /****************************************************************************** * 时间设定 ******************************************************************************/ void Time_Set(struct TIME Time) { DS1302_Init(); Byte_Send(Ctr_W); //单字节写 Byte_Send(0x00); //允许写 DS1302_Init(); Byte_Send(Bst_W); //突发写入 Byte_Send(Time.Second); //秒 Byte_Send(Time.Minute); //分 Byte_Send(Time.Hour); //时 Byte_Send(Time.Day); //日 Byte_Send(Time.Month); //月 Byte_Send(Time.Week); //周 Byte_Send(Time.Year); //年 Byte_Send(0x80); //禁止写 CLK=0; RST=0; } /****************************************************************************** * 读取时间 ******************************************************************************/ unsigned char * Time_Read(void) { unsigned char tm[7]; DS1302_Init(); Byte_Send(Bst_R); tm[0]=Byte_Rcv(); //秒 tm[1]=Byte_Rcv(); //分 tm[2]=Byte_Rcv(); //时 tm[3]=Byte_Rcv(); //日 tm[4]=Byte_Rcv(); //月 tm[5]=Byte_Rcv(); //周 tm[6]=Byte_Rcv(); //年 RST=0; return tm; } Maplead MCU Development Board http://shop63914145.taobao.com 123 18. 红外遥控 红外遥控组成 红外遥控是一种将信息调制到 38KHz 的红外载波上从而传递信息的一种手 段,以其体积小、功耗低以及低成本等优点广泛地被应用于家用电器、玩具等领 域中。 红外遥控由两部分组成,分别为发射部分和接收部分。发射部分由编码芯片 和红外二极管构成,主要完成控制码的调制和发射。接收部分由红外接收头和解 码电路构成,主要完成红外调制码的接收和解调。 目前,红外接收头大都采用红外一体化接收头,该接收头集接收、放大、滤 波等功能于一体。当红外一体化接收头接收到 38KHz 的红外载波后,在其 OUT 引脚上输出低电平;当没有接收到 38KHz 红外载波时,其 OUT 引脚由 30KΩ 的 电阻拉至高电平。其内部结构如图 18-2 所示。 图 18-1 红外一体化接收头 图 18-2 红外一体化接收头内部结构图 Maplead MCU Development Board http://shop63914145.taobao.com 124 红外遥控编码 红外遥控编码原理是将所要传递的数据串行化,一位一位地调制到红外载波 上加以传输。红外遥控传递的“0”、“1”数字码采用脉宽调制的方式加以区分。当 传递数字“0”时,脉宽为 0.565ms、间隔 0.56ms、周期为 1.125ms,其占空比为 1/2;当传递数字“1”时,脉宽为 0.565ms、间隔 1.685ms、周期为 2.25ms,其占 空比为 1/4。 图 18-3 数字“0”和“1”的发射码 (一体化接收头 OUT 引脚输出的电平刚好跟发射电平相反) 为了增强红外遥控系统的抗干扰能力,欲发射的数据经过串行化后,调制芯 片会将发射码调制到 38KHz 的红外载波上。当输出高电平时,红外二极管发射 38KHz 的红外线,当输出低电平时,红外二极管不发射红外线。 当红外遥控发射一组信号的时候,会先发射一段引导码,以告诉接收系统做 好接收准备。引导码由 9ms 的高电平和 4.5ms 的低电平构成(不同遥控器可能不 同,如引导码由 4.5ms 高电平和 4.5ms 的低电平构成),如图 18-4 所示。 图 18-4 引导码 当按下遥控器后,发射系统首先发送引导码,紧跟引导码的是 16 位长度的 用户码,用户码的作用是用来区别不同的电器设备,每一台电器设备的用户码都 应该是不同的。 图 18-5 红外遥控系统的数据串 Maplead MCU Development Board http://shop63914145.taobao.com 125 用户码发射完后接下来便是 8 位的数据码和 8 位的数据码反码。数据码即是 对电器设备的控制信号,而数据码反码的是对数据的纠错以提高红外遥控系统的 抗干扰能力。 如图 18-5 所示,用户码和数据码的发射都是低位在前,高位在后。数据码 反码后紧跟一位结束码,为一个 0.56ms 的低电平。 当遥控器的某个按键被按下并持续 108ms 后,发射系统发射一个重复码, 并每隔 108ms 发射一次重复码。该重复码由 9ms 的高电平和 2.25ms 的低电平以 及一个高电平短脉冲构成。 图 18-6 红外遥控的重复码 当红外一体化接收头接收到遥控器的发射信号时,编码中相应的高电平由接 收头的 OUT 口输出一个低电平,编码中的低电平由接收头的 OUT 口输出一个 高电平。通俗地讲就是,当一体化接收头接收到 38KHz 红外信号后,OUT 口就 输出低电平,没有收到就被拉为高电平。 51 单片机红外遥控发射模拟 红外发射频率为 38KHz,因此一个周期的时间为 26.315789…微秒,取整数 为 26us,亦即,13us 的高电平和 13us 的低电平。 由于一个 51 单片机定时器数量有限,很难同时发射红外编码,又同时解码, 因此,本示例仅演示红外发射头发射 38KHz 的红外编码时,红外一体化接收头 接收红外编码并点亮流水灯的第一个 LED。 108ms 108ms 重复码 重复码 Maplead MCU Development Board http://shop63914145.taobao.com 126 红外遥控实验电路连接图示 图 18-6 红外遥控实验前用短路帽连接“R”或“T”端口 单独用遥控器做接收实验时,“T”端口不必连接。 平时不做该实验时,将短路子拔掉,以免接收头对单片机造成干扰。 例程 18-2 红外解码程序 /****************************************************************************** * 说明: * (1)晶振 12Mhz 调试通过。 * (2)用跳线帽将红外接收头的输出口与单片机的 P3.3 引脚相连接。 * (3)因为红外接收头为脉冲型,接收到 38KHz 载波后会输出低电平, * 但当载波持续的时间很长时,接收头并不一直输出低电平,而 * 是输出一段时间(大概几十 ms?但不管怎样,一定大于接收协议 * 的最长载波发射时间 9ms)后停止输出低电平,此时应该停止发 * 射载波,延时一会,重新开始新的发送,接收头才重新开始输 * 出低电平。 * (4)启动程序后,LED1 会不停闪烁,用不透光的金属片或者黑纸片 * 阻挡发射管与接收头之间,LED1 停止闪烁。 * 作者:Shenney John ******************************************************************************* * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #define T0_Run(); ET0=1;EA=1;TR0=1; void T0_Init(void); Maplead MCU Development Board http://shop63914145.taobao.com 127 sbit IRLED=P2^3; //红外发射头接口 sbit IR =P3^3; //红外接收头接口 sbit LED =P1^0; //发光二极管接口 void main(void) { unsigned int i=0,j=0; T0_Init(); T0_Run(); IR=1; LED=1; //初始化为熄灭 LED EA=1; while(1) { if(!IR) //如果红外接收头接收到信号(低电平) LED=IR; //点亮 LED(D1,流水灯第一个) else LED=1; //如果没有收到信号,熄灭 LED i++; if(i==10000) //38KHz 载波发射一段时间后,停止发射 { i =0; EA=0; //停止定时中断,停止发射载波 IRLED=1; //关闭红外 LED for(j=0;j<5000;j++); //停止发射一段时间 EA=1; //重新开始发射 38KHz 载波 } } } /***************************************************** * 定时器 0 初始化函数 ******************************************************/ void T0_Init(void) { TMOD=0x02; //T0 为 8 位自动重装模式 TH0 =0xF3; //装初值,定时 13us Maplead MCU Development Board http://shop63914145.taobao.com 128 TL0 =0xF3; } /***************************************************** * 定时器 0 中断处理函数 ******************************************************/ void T0_ISR() interrupt 1 using 1 { IRLED=~IRLED; //发射管电平每 13us 反相一次,输出载波 } 图 18-7 红外接收发射电路原理图 51 单片机红外遥控接收解码设计 不管是引导码,数字“0”或“1”还是结束码以及重复码,都以发射 38KHz 的 红外载波作为开始。当一体化接收头接收到红外载波后即在 OUT 口输出一低电 平。因此,我们将一体化接收头的 OUT 口连接至 51 单片机的外部中断输入口(如 图 18-7 所示,当进行红外接收试验时,要将接收口用短路子连接至 P3.3 端口处), 将外部中断触发方式设定为下降沿触发,这样在每一次下降沿触发外部中断的时 候我们都做两件事情:(1) 取出上次定时器启动后至现在所经历的时间(引导码 除外);(2) 清零定时器并开始新的计时(接收完 4 个字节的数据后结束计时)。 如果取出的定时值约为 13.5ms(或 9ms)则可判断为引导码; 如果取出的定时值约为 1.125ms,则可判断为数值“0”; 如果取出的定时值约为 2.25ms,则可判断为数值“1”; Maplead MCU Development Board http://shop63914145.taobao.com 129 如果取出的定时值约为 11.25ms(或 6.75ms),则可判断为重复码。 (因为实际操作中,由于晶振的偏差等原因,解码时的定时值要有一定的余 量,因此,不能绝对等于定时值,应该取一定的范围。) 例程 18-2 红外解码程序 /******************************************************************** * 说明: * (1)晶振 12Mhz 调试通过。 * (2)用跳线帽将红外接收头的输出口与单片机的 P3.3 引脚相连接。 * 作者:Shenney John ********************************************************************* * Copyright (C) 2010 by Shenney John, All Rights Reserved. ********************************************************************/ #include #include "typedef.h" #include "display.h" #define T0_Run() ET0=1;TR0=1 #define T0_Stop() TR0=0;ET0=0 void EX1_Init(void); void T0_Init(void); void IR_Decode(void); void Decode_Stop(void); void Display(unsigned char, unsigned char); void delay(); unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; //数码管显示段码 unsigned char code LED_Bit[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; //数码管显示位码 unsigned int IRCode[32]; //32 个数据码 unsigned char MCode=0, UCode=0; //机器码和用户码 unsigned char IRCnt=0; //接收码计数 bit RptCode=0; //是否为重复码标志 bit DecodeStart=0; //开始译码标志 void main(void) { unsigned char i=0; Maplead MCU Development Board http://shop63914145.taobao.com 130 EX1_Init(); T0_Init(); EA=1; while(1) { if(DecodeStart) IR_Decode(); Display(i, UCode); //显示重复次数和编码值 if(RptCode) { i++; RptCode=0; } } } /***************************************************** * 红外解码 ******************************************************/ void IR_Decode(void) { unsigned char i, M1,M2, U1,U2; for(i=0;i<8;i++) //解码第 1 个机器码 { M1 <<=1; if(*(IRCode+i)>=1000 && *(IRCode+i)<=1200) M1 &=0xFE; if(*(IRCode+i)>=2100 && *(IRCode+i)<=2300) M1 |=0x01; } for(i=8;i<16;i++) //解码第 2 个机器码 { M2 <<=1; if(*(IRCode+i)>=1000 && *(IRCode+i)<=1200) M2 &=0xFE; if(*(IRCode+i)>=2100 && *(IRCode+i)<=2300) M2 |=0x01; } Maplead MCU Development Board http://shop63914145.taobao.com 131 for(i=16;i<24;i++) //解码第 1 个用户码 { U1 <<=1; if(*(IRCode+i)>=1000 && *(IRCode+i)<=1200) U1 &=0xFE; if(*(IRCode+i)>=2100 && *(IRCode+i)<=2300) U1 |=0x01; } for(i=16;i<24;i++) //解码第 2 个用户码 { U2 <<=1; if(*(IRCode+i)>=1000 && *(IRCode+i)<=1200) U2 &=0xFE; if(*(IRCode+i)>=2100 && *(IRCode+i)<=2300) U2 |=0x01; } if(M1==~M2) //判断机器码是否互为反码 if(U1==U2) //如果机器码与用户码都正确,赋值 { UCode=U1; MCode=M1; } //如果机器码或用户码有误,什么也不做 } /***************************************************** * 外部中断 1 初始化函数 ******************************************************/ void EX1_Init(void) { IT1=1; //外部中断 1 为跳变沿触发 EX1=1; //使能外部中断 1 } /***************************************************** * 定时器 0 初始化函数 ******************************************************/ void T0_Init(void) { TMOD=0x01; //T0 为 16 位定时模式 TH0 =0x00; //装初值 TL0 =0x00; Maplead MCU Development Board http://shop63914145.taobao.com 132 } /***************************************************** * 外部中断 1 处理函数 ******************************************************/ void EX1_ISR(void) interrupt 2 using 1 { unsigned int Header; T0_Stop(); if(IRCnt==0) //如果接收到第一个脉冲 { T0_Run(); //开始计时至下一个脉冲到来 } if(IRCnt==1) //如果引导码已接收完毕 { Header =TH0; //取计时值 Header<<=8; Header |=TL0; T0_Init(); //清零计时器 T0_Run(); //开启下一位编码计时 if((Header<13000) || (Header>14000)) //如果不是引导码 { if((Header<11000) || (Header>12000)) //如果不是重复码 Decode_Stop(); //停止解码 else //如果是引导码 RptCode=1; //引导码标志置位 } } //引导码判断通过后继续执行以下代码 if(IRCnt>1) //引导码后,每一位数据都由此处代码处理 { IRCode[IRCnt-2] =TH0; //存储每一位接收到的编码值 IRCode[IRCnt-2]<<=8; //第一个有效数位时,IRCnt 已经为 2 IRCode[IRCnt-2] |=TL0; //所以要减去 2,这样可使数组标号从 0 开始 T0_Init(); T0_Run(); } IRCnt++; Maplead MCU Development Board http://shop63914145.taobao.com 133 if(IRCnt>=34) //如果收到了结束位 { IRCnt=0; //清零接收计数 DecodeStart=1; //接收结束可以译码 } if(TR0==0) IRCnt=0; //如果解码被停止,则清零计数 } /***************************************************** * 定时器 0 中断处理函数 ******************************************************/ void T0_ISR() interrupt 1 using 2 { Decode_Stop(); //如果 T0 发生溢出,则停止译码 } /***************************************************** * 显示函数 ******************************************************/ void Display(unsigned char Rpt_Code, unsigned char U_Code) //Rpt_Code:重复次数;U_Code:用户码 { unsigned char i; P0=0x00; P2=LED_Bit[0]; P0=LED_Seg[U_Code & 0x0F]; //取用户码低 4 位 for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[U_Code>>4]; //取用户码高 4 位 for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[3]; P0=LED_Seg[Rpt _Code & 0x0F]; //取机器码低 4 位 for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[4]; Maplead MCU Development Board http://shop63914145.taobao.com 134 P0=LED_Seg[Rpt _Code>>4]; //取机器码高 4 位 for(i=0;i<200;i++); P0=0x00; } /***************************************************** * 停止解码函数 * (1)此函数执行后,解码处理被重置。 ******************************************************/ void Decode_Stop(void) { T0_Stop(); T0_Init(); IRCnt=0; } Maplead MCU Development Board http://shop63914145.taobao.com 135 19. AD 转换器 TLC549 8 位串口 AD 转换器 TLC549 TLC549为德州仪器公司采用CMOS工艺生产的8位串口高精度AD转换器, 其基本参数为: „ 8 位精度,误差为±0.5LSB。 „ 差分模拟电压输入。 „ 最大转换时间 17us,40KHz 的转换速率。 „ 串口输出数据,最大通信时钟频率 4MHz。 „ 运行电压范围宽,3V~6V。 „ 低功耗,最大功耗 15mW,适合电池供电系统应用。 „ 运行温度范围为 0~70℃℃(商业级),-40 ~85℃℃(工业级)。 TLC549 的引脚定义 图 19-1 TLC549 引脚定义 表 19-1 TLC549 引脚说明 引脚 定义 REF+ 正参考电压输入脚。 ANALOG IN 模拟电压输入口。 REF- 负参考电压输入脚。 GND 电源地。 CS 片选,低电平有效。 DATA OUT 数据输出口。 I/O Clock 同步时钟输入端。 VCC 电源。 REF+即为 AD 的最高转换电压,模拟输入电压超过 REF+时,转换结果为 Maplead MCU Development Board http://shop63914145.taobao.com 136 0xFF;REF-即为 AD 的最低转换电压,模拟输入电压低于 REF-时,转换结果为 0x00。因此,AD 转换器的分辨率为:(V REF+- VREF-)/256。 TLC549 的操作 图 19-2 TLC549 的数据读取 如图 19-2 所示,当对 TLC549 进行操作的时候要先将 CS 拉低 1.4us(ten) 以上,以使能数据读取。 随着同步时钟的输入,数据从 DATA OUT 口由高位到低位依次输出。 数据的最高位 A7 在 CS 拉低的后即已输出到 DATA OUT 口上。 其他 7 位数据(A6~A0)都在每个同步时钟的下降沿被输出到 DATA OUT 口上。 读取完一个 8 位数据后 CS 要拉高至少 17us 以使 TLC549 进行下一次的 AD 转换。 TLC549 第一次 AD 转换是通过一个伪读取启动的,即拉低 CS,输入 8 个 同步时钟,但不读取数据。第一次 AD 转换启动后,接下来的 AD 转换都在读取 完一个字节数据并拉高 CS 后自动进行。 Maplead MCU Development Board http://shop63914145.taobao.com 137 开发板 AD 转换器实验电路连接 图 19-3 AD 转换器实验电路连接 TLC549 的模拟输入端有 4 种输入方式,通过拨码开关选择输入: (1) 热敏电阻分压输入(电压变化不明显); (2) 光敏电阻分压输入,电压随光强度变化明显; (3) 可调电阻分压输入,电压随电阻阻值变化而变化; (4) 外部模拟电压输入端,输入电压范围为 0~5V。 当拨码开关全部拨至左边的时候(OFF),可以从外部输入电压信号进行 AD 转换实验,注意,外部输入的排针下面标有电压信号的正负性,“IN”端输入正电 压,GND 输入负电压。外部输入电压范围为 0~5V。 当拨码开关的第 1 个开关拨至右侧(ON)时,热敏电阻、光敏电阻以及可 调电阻都接通电源,但还没有将电压信号连接至 AD 转换器。 当将第 1 个开关拨至右侧,同时第 2 个开关(RT)拨至 ON 时,热敏电阻 接通,将手指头触摸热敏电阻时,AD 转换的信号会有所变化(但数值变化不大)。 当将第 1 个开关拨至右侧,同时第 3 个开关(RL)拨至 ON 时,光敏电阻 接通,随着周围光线(可用手遮挡)的明暗变化,AD 数值也跟着变化。 当将第 1 个开关拨至右侧,同时第 4 个开关(RW)拨至 ON 时,可调电阻 接通,用小螺丝刀调整可调电阻旋钮, AD 数值也跟着发生变化。 注意:VCC 开关拨至 ON 后,每次只能打开一路模拟输入(RT、RL 或 RW), 拨码开关 热敏电阻 光敏电阻 可调电阻 外部输入 Maplead MCU Development Board http://shop63914145.taobao.com 138 如果一次同时打开多路输入则 AD 转换结果为两路模拟信号的叠加。 TLC549 AD 转换演示程序 图 19-4 AD 转换器电路连接图 例程 19-1 TLC549AD 转换程序 /****************************************************************************** * (1)晶振 12Mhz 调试通过 * (2)AD 转换。 * (3)将 AD 模块的拨码开关 VCC 拨到右边 ON 的位置,此时,可调电阻、热敏电阻 * 以及光敏电阻都接通电源。分别(每次只能接通其中一个)将 RT(热敏)、RL(光敏)、 * RW(可调)开关拨至右侧的 ON 位置,AD 转换器便能分别测定加在该电阻元件上 * 的电压。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #include /**************************************** * 宏定义延时操作 ****************************************/ #define Delay1us(); {_nop_();} #define Delay2us(); {_nop_();_nop_();} #define Delay4us(); {Delay2us();Delay2us();} #define Delay8us(); {Delay4us();Delay4us();} #define Delay10us(); {Delay8us();Delay2us();} #define Delay17us(); {Delay10us();Delay4us();Delay2us();Delay1us();} sbit CLK = P2^3; //定义时钟线 sbit DOUT = P2^4; //定义数据线 Maplead MCU Development Board http://shop63914145.taobao.com 139 sbit AD_CS= P1^3; //定义片选线 sbit DS_CS=P1^2; //实时时钟片选 sbit DA_CS=P1^4; //DA转换器片选 void Display(unsigned char); void AD_Init(void); unsigned char AD_Convert(void); void main(void) { unsigned char Data, i; DS_CS=0; //关实时时钟片选 DA_CS=1; //关 DA 转换器片选 AD_Init(); //AD 转换器初始化 while(1) { Data=AD_Convert(); for(i=0;i<120;i++) Display(Data); } } /************************************** AD 转换器初始化函数 ***************************************/ void AD_Init(void) { unsigned char i; AD_CS=0; //使能片选 CLK =0; //拉低时钟 Delay2us(); //延时 for(i=0;i<8;i++) //给 8 个初始化时钟 { CLK=1; CLK=0; } AD_CS=1; //关片选,器件开始 AD 转换 Delay17us(); //器件转换时间 } /*************************************** * AD转换函数 ***************************************/ unsigned char AD_Convert(void) { unsigned char Data, i; DOUT =1; //将数据口设为输入状态 AD_CS=0; //使能片选 CLK =0; //拉低时钟 Maplead MCU Development Board http://shop63914145.taobao.com 140 Delay2us(); //等待器件送数据到总线上 for(i=0;i<8;i++) //接收数据 { Data<<=1; //将最低位向高位移一位 CLK =1; Data |=DOUT; //将数据线上的某位放入数据的最低位 CLK =0; } AD_CS=1; //接收完毕,关片选 Delay17us(); //器件下个数据转换的时间 return Data; } /*************************************** * 数据显示函数 ***************************************/ void Display(unsigned char Data) { unsigned char code LED_Seg[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; unsigned char code LED_Bit[]={0,1,2,3,4,5,6,7}; unsigned char Hundred_Bit, Ten_Bit, Single_Bit, i; Single_Bit=Data%10; //取出个位 Ten_Bit =(Data/10)%10; //取出十位 Hundred_Bit=Data/100; //取出百位 P0=0x00; //显示个位 P2=LED_Bit[0]; P0=LED_Seg[Single_Bit]; for(i=0;i<100;i++); if(Data>=10) //如果数字大于等于 10,显示十位 { P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[Ten_Bit]; for(i=0;i<100;i++); } if(Data>=100) //如果数字大于等于 100,显示百位 { P0=0x00; P2=LED_Bit[2]; P0=LED_Seg[Hundred_Bit]; for(i=0;i<100;i++); } P0=0x00; } Maplead MCU Development Board http://shop63914145.taobao.com 141 20. DA 转换器 TLC5615 10 位串口 DA 转换器 TLC5615 TLC5615 为德州仪器公司采用 CMOS 工艺生产的 10 位 3 线串口高精度 DA 转换器,其基本参数为: „ 10 位精度电压输出型 CMOS 工艺 DA 转换器。 „ 5V 单电源供电。 „ 内部上电复位。 „ 电压输出范围为 0V~2 倍参考电压。 „ 参考电压输入阻抗高,10MΩ。 „ 典型建立时间 12.5us。 „ 3 线串口输入数据,最大通信时钟频率 1.21MHz。 „ 低功耗,最大功耗 1.75mW。 „ 端口输出电流能力为 20mA。 „ 运行温度范围为 0~70℃℃(商业级),-40 ~85℃℃(工业级)。 TLC5615 的引脚定义 图 20-1 TLC5615 引脚定义 表 20-1 TLC5615 引脚说明 引脚 定义 DIN 数据输入口。 SCLK 同步时钟输入端。 CS 片选,低电平有效。 DOUT 链式串行数据输出,可将数据同时传递给其他器件。 Maplead MCU Development Board http://shop63914145.taobao.com 142 AGND 模拟地。 REFIN 参考电压,亦即 TLC5615 能够输出的最大电压的一半。 OUT 模拟输出口。 VDD 电源。 TLC5615 的操作 图 20-2 TLC5615 的数据写入 当器件的 CS 片选为高电平时,同步时钟输入端应该为低电平,以使时钟的 馈入电流最小化。 TLC5615 在数据传输过程中片选建立时间及数据读取时间等都很快,均为 50ns 以下,所以,当单片机送片选信号后就可直接输入同步时钟传递数据。 在向 TLC5615 发送数据的时候,10 位数据高位在前,低位在后,在每个时 钟信号的低电平处将欲发送的数据送到 DIN 线上,在每个时钟信号的上升沿 TLC5615 将 DIN 线上的数据读入内部移位寄存器中。 对 TLC5615 写数据有两种方式,分别为 12 位方式和 16 位模式。 图 20-3 12 位方式的数据结构 线路中只有一个 TLC5615 器件的时候采用 12 位模式,该模式将 10 位有效 数据存入 12 位数据的高 10 位,低 2 位可以为任何数。 如果线路中有多个 TLC5615 器件的时候,数据输入采用 16 位方式。该方式 Maplead MCU Development Board http://shop63914145.taobao.com 143 下,可以将其中一个 TLC5615 作为主器件,其他 TLC5615 器件的 DIN 脚连接至 主 TLC5615 的 DOUT 脚处。16 位数据的高 4 位和低 2 位为无用数据,可以为任 何数,DB2~DB11 为有效的 10 位数据。数据传输时,同样在每个时钟的上升沿 TLC5615 将数据读入内部移位寄存器中,在每个时钟的下降沿,主 TLC5615 器 件将先前读到的数据送到 DOUT 口,从而使其他 TLC5615 器件得以读取单片机 送来的 16 位数据。当主器件的 16 位数据读取完毕之后,其他 TLC5615 器件只 读取了 15 位数据,因此,还需要一个额外的时钟信号来读取最后一位数据。 图 20-3 12 位方式的数据结构 数据传输完成后,时钟信号线拉低,CS 片选信号线拉高后,则本次数据传 输结束,TLC5615 会将读取到的数据送入 DA 转换单元中进行 DA 转换。 数据输入时,数据的高位在前,低位在后,在同步时钟的每个上升沿器件将 一位数据读入内部的移位寄存器。 DA 转换器实验电路连接 图 20-4 DA 转换控制 LED 的亮度 用短路子将 DA 的输出端口(OUT)与 LED 进行连接,则 DA 转换后的电 压加在了 LED 上,如果输出电压变化,LED 的亮度也产生变化,但这种变化是 在一定范围内的,电压过低 LED 不亮,电压过高 LED 亮度变化不明显。 可用电压表测量 DA 输出的电压值,OUT 端口接电压表的正输入端,GND Maplead MCU Development Board http://shop63914145.taobao.com 144 接电压表的负输入端。 TLC615 DA 转换演示程序 图 20-4 TLC5615DA 转换电路原理图 例程 20-1 TLC5615 DA 转换程序 /****************************************************************************** * 说明: * (1)晶振 12Mhz 调试通过 * (2)由于 3 个器件都在一个总线上,所以实验中要关闭其他 3wire 总线器件的片选以 避免误操作。 * (3)用短路帽将 DA 转换器的 LED 与 OUT 针短接。 * (4)LED 亮度到了一定程度不再变化,因为 LED 亮度与电压不总成正比。 * 作者:Shenney John ******************************************************************************* * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include sbit DS_CS = P1^2; //实时时钟片选 sbit AD_CS = P1^3; //AD 转换器片选 sbit CLK = P2^3; //定义时钟线 sbit DIN = P2^4; //定义数据线 sbit DA_CS = P1^4; //定义片选线 void DA_Converter(unsigned int); Maplead MCU Development Board http://shop63914145.taobao.com 145 void main(void) { unsigned int i, j; AD_CS =1; //关 AD 转换器片选 DS_CS =0; //关实时时钟片选 while(1) { for(i=280;i<1024;i++) //不从 0 开始计数是因为,发光二极管需要一定的电压才开始 发光 { DA_Converter(i); //启动转换 for(j=0;j<5000;j++); //给器件一定的电压建立时间 } } } ********************************************************************/ * DA转换函数 ********************************************************************/ void DA_Converter(unsigned int Data) { unsigned char i; Data<<=2; //按照 TLC5615 的数据格式调整数据 CLK=0; DA_CS=0; //开片选,准备发送数据 for(i=0;i<16;i++) //发送数据 { Data<<=1; //每次都将数据左移一位,以将数据最高位移入 CY 位 DIN=CY; CLK=1; CLK=0; } DA_CS=1; } Maplead MCU Development Board http://shop63914145.taobao.com 146 21. SD 卡的 SPI 方式读写 SD 卡及其总线结构 SD 卡是日常生活中常见的一种电可擦除移动存储设备,因其存储量大、价 格低廉而被广泛应用于数码相机、手机等数码产品中。 SD 卡支持两种总线方式:SD 方式与 SPI 方式。其中 SD 方式采用 6 线制, 使用 CLK、CMD、DAT0、DAT1、DAT2、DAT3 进行数据通信,其特点是数据 位数宽(4 位)、速度快。SPI 方式采用 4 线制,使用 CS、CLK、DataIn、DataOut 这 4 个端口进行数据通信,其特点是速度要比 SD 方式慢,但总线简单、不需要 进行 CRC 校验,因而比较适合单片机采用这种方式对 SD 卡进行读写操作。 图 21-1 SD 卡及其接口 表 21-1 SD 卡接口定义 说明 端口 SD 模式 SPI 模式 1. DAT3/CS DAT3 口。 片选,低电平有效。 2. CMD/DataIn 命令/回应。 数据输入端。 3. VSS1 电源地。 电源地。 4. VDD 电源。 电源。 5. CLK/SCK 同步时钟。 同步时钟。 6. VSS2 电源地。 电源地。 7. DAT0/DataOut DAT0 口。 数据输出端。 8.DAT1 DAT1 口。 NC。 9.DAT2 DAT2 口。 NC。 SD 卡命令格式 SD 卡的命令字由 6 个字节组成,其组成结构见图 21-2。 Maplead MCU Development Board http://shop63914145.taobao.com 147 命令字的第 1 个字节为命令号(CMD0、CMD1 等),命令号的最高位始终 为 0,次高位(位 7)为 1,表示命令是由主机向 SD 卡发送的命令。 命令字的第 2、3、4、5 字节为命令参数表,传送随命令附带的参数,如地 址信息等。 命令字的最后一个字节为 CRC 校验字节,其中该字节的高 7 位为 CRC 码, 最后一位为结束位,始终为 1。 Byte1* Byte2 Byte3 Byte4 Byte5 Byte6 0 1 x x x x x x 参数 参数 参数 参数 7 位 CRC 1 * X 表示该位可以为“0”或者“1”。 图 21-2 SD 卡命令字结构 当主机向 SD 卡发送一个命令后,SD 卡会首先向主机发送一个相应码,如 果指令没有错误 SD 卡接下来便会执行主机发来的命令。 SD 卡复位至 SPI 方式 SD 卡默认的读写方式为 SD 模式,要使用 SPI 模式对 SD 卡进行读写,需要 在 SD 卡上电后对 SD 卡写入 CMD0 和 CMD1 命令。在两条命令写入 SD 卡后, 如果一切正常,SD 卡会进入 SPI 模式,从而可以方便地采用单片机对 SD 卡进 行 SPI 方式的读写操作。 图 21-3 对 SD 卡的复位操作时序 当 SD 卡完成上电后,先对 SD 卡发送 74 个以上的同步时钟。 然后向 SD 卡发送 CMD0 命令(因命令号的最高位始终为 0,次高位为 1, 因此发送给 SD 卡的命令是 0 与 0x40 进行或运算的结果)。 命令字的第 2、3、4、5 字节皆为 0x00。 Maplead MCU Development Board http://shop63914145.taobao.com 148 命令字的第 6 字节为 CRC 校验字节,固定为 0x95。 命令字发送完成后,发送若干个 8 位的同步时钟,直至 SD 卡发出响应字节 0x01。 接收完 SD 卡的响应字节后,CS 线拉高,再发送 8 个空时钟。 图 21-4 将 SD 卡初始化为 SPI 方式时序 当 SD 卡执行完复位过程后,接着向 SD 卡发送初始化指令 SMD1,以激活 SD 卡 SPI 方式。 首先发送指令号 CMD1(0x01|0x40=0x41),然后发送 4 个 0x00 字节,最 后发送 CRC 校验码,此处为 0xFF,原因是此时 SD 卡已经工作在 SPI 模式,在 SPI 模式下,SD 卡默认为不进行 CRC 校验,因此我们可以随意写入一个 0xFF 字节以填充满整个命令字的结构。 当向 SD 卡发送完 CMD1 指令后,发送若干个 8 位的同步时钟,直至 SD 卡 发出响应字节 0x00。 接收完 SD 卡的响应字节后,CS 线拉高,再发送 8 个空时钟。 至此,我们完成了 SD 卡的复位及进入到 SPI 方式的所有步骤。 SD 卡的 SPI 方式读写 SD 卡读写一次的数据量必须为 512 字节的整数倍,亦即,对 SD 卡读写操 作的最少数据量为 512 字节。我们也可以通过向 SD 卡写修改扇区大小的指令 CMD16 以使每次读写的数据量变为(n×512)字节(n≥1),本文中我们使用 SD 卡默认的一次操作 512 字节的模式对 SD 卡进行读写操作。 Maplead MCU Development Board http://shop63914145.taobao.com 149 对 SD 卡的单数据块读操作: 图 21-5 对 SD 卡进行单数据块读操作时序 如图 21-4 所示,对 SD 卡读操作的时序为: (1) 写入读单数据块命令 CMD17(0x11|0x40=0x51)。 (2) 写 4 个地址参数,4 个字节凑成一个 32 位的地址值,第一个字节是 32 位地址值的最高 8 位数据,第 4 个字节是 32 位地址值的最低 8 位 数据。 (3) 写 CRC 校验位 0xFF。 (4) 写若干个 0xFF 的空操作。 (5) SD 卡发送 0x00 响应。 (6) 写若干个 0xFF 的空操作。 (7) SD 卡发送 0x FE 数据头。 (8) SD 卡发送指令指定地址的 512 字节数据块。 (9) SD 卡发送两字节的 CRC 校验码,由于 SPI 模式默认不需要 CRC 校 验,因此这两个字节的数据可丢弃不用。 (10)拉高 CS,发送 8 个空时钟。 至此,我们完成了对 SD 卡指定地址数据块的读操作。 Maplead MCU Development Board http://shop63914145.taobao.com 150 对 SD 卡的单数据块写操作: 图 21-6 对 SD 卡进行单数据块写操作时序 如图 21-4 所示,对 SD 卡读操作的时序为: (1) 写入读单数据块命令 CMD24(0x18|0x40=0x58)。 (2) 写 4 个地址参数,4 个字节凑成一个 32 位的地址值,第一个字节是 32 位地址值的最低 8 位数据,第 4 个字节是 32 位地址值的最高 8 位 数据。 (3) 写 CRC 校验位 0xFF。 (4) 写若干个 0xFF 的空操作。 (5) SD 卡发送 0x00 响应。 (6) 写若干个 0xFF 的空操作。 (7) 写 0x FE 数据头,表示接下来要发送 512 字节的数据块。 (8) 写 512 字节数据块。 (9) 写两字节的 0xFF 作为 CRC 校验码的填充字节。 (10)SD 卡发送 xxx00101B 响应码。 (11)在 SD 卡将 512 字节数据向指定地址写完之前,其数据输出断时钟被 拉低。 (12)SD 卡释放数据输出线 DataOut。 Maplead MCU Development Board http://shop63914145.taobao.com 151 (13)拉高 CS,发送 8 个空时钟。 至此,我们完成了对 SD 卡指定地址数据块的写操作。 图 21-7 SD 卡电路连接原理图 SD 卡电路连接实物图 图 21-8 SD 卡电路连接实物图 用杜邦线将 P3.4 口连接至 SD 模块的 CLK 端口; 用杜邦线将 P3.5 口连接至 SD 模块的 DI 端口; Maplead MCU Development Board http://shop63914145.taobao.com 152 用杜邦线将 P3.6 口连接至 SD 模块的 DO 端口; 用杜邦线将 P3.7 口连接至 SD 模块的 CS 端口; 将一张 2G 容量以下(2G 以上没有测试过)的 SD 卡插入 SD 卡槽就可以进 行该实验了。 SD 卡 SPI 方式读写演示程序 例程 21-1 SD 卡 SPI 方式读写 /****************************************************************************** * 说明: * (1)晶振 12MHz 调试通过。 * (2)2G 以下 SD 卡 SPI 方式读写驱动程序。 * (3)对 SD 卡操作要以块为单位进行操作(地址为 512 的整数倍;数据量为 512 的整 * 数倍)。 * (4)向 SD 卡中写数据时,尽量避开卡开始部分的地址(本程序数据写入点为 51200 * 地址以后的空间),不然可能会造成 SD 卡无法识别、无法格式化等问题(可用 SD * 专用格式化软件解决)! * (5)请确保您的 SD 卡内没有个人资料,不然数据会丢失!!!!!!!!!!!!! * (6)建议采用价格便宜的工厂用测试卡运行本程序,对于运行本程序有可能造成的 * SD卡损坏等情况,本程序作者及开发板生产销售商不承担任何责任!!!!!! * (7)如果单片机内部的 RAM 不够大,读入的数据块将会部分丢失,但不影响程序的 * 演示 (例如 STC89C52RC 内部的 xdata 空间容量为 256Byte,当所取数据块超过 * 256字节时内存溢出,数据丢失。如果超出存储空间读数据,取出的数据都为 * 0xFF)。 * (8)测试时如果 SD 卡中途无反应,彻底关闭开发板电源,重新启动。 * (9)测试时,先用杜邦线将单片机输出端口与对应的 SD 卡 SPI 接口相连: * P3.4---->SD 卡 SPI 接口的 CLK * P3.5---->SD 卡 SPI 接口的 DI * P3.6---->SD 卡 SPI 接口的 DO * P3.7---->SD 卡 SPI 接口的 CS * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include sbit CLK = P3^4; //时钟线 sbit DI = P3^5; //数据输入线(相对 SD 卡为输入,单片机刚好相反) sbit DO = P3^6; //数据输出线(相对 SD 卡为输出,单片机刚好相反) sbit CS = P3^7; //片选线 void Display(unsigned char ); void SPI_W(unsigned char); unsigned char SPI_R(void); unsigned char SD_Response(void); void SD_Cmd(unsigned char, unsigned long, unsigned char); unsigned char SD_Init(void); unsigned char SD_Block_W(unsigned char, unsigned long, unsigned int); unsigned char * SD_Block_R(unsigned long, unsigned int); Maplead MCU Development Board http://shop63914145.taobao.com 153 unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};//数码管段码 unsigned char code LED_Bit[]={0x00, 0x01}; //数码管位码 unsigned char xdata *DATA; //指向数据块的指针 unsigned char code Test_1[]={ //测试数据块 1 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F, 0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF, 0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F, 0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF, 0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, }; unsigned char code Test_2[]={ //测试数据块 2 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F, 0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF, Maplead MCU Development Board http://shop63914145.taobao.com 154 0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, 0X00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0X0B,0X0C,0X0D,0X0E,0X0F, 0X10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0X1B,0X1C,0X1D,0X1E,0X1F, 0X20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0X2B,0X2C,0X2D,0X2E,0X2F, 0X30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0X3B,0X3C,0X3D,0X3E,0X3F, 0X40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0X4B,0X4C,0X4D,0X4E,0X4F, 0X50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0X5B,0X5C,0X5D,0X5E,0X5F, 0X60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0X6B,0X6C,0X6D,0X6E,0X6F, 0X70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0X7B,0X7C,0X7D,0X7E,0X7F, 0X80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0X8B,0X8C,0X8D,0X8E,0X8F, 0X90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0X9B,0X9C,0X9D,0X9E,0X9F, 0XA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0XAB,0XAC,0XAD,0XAE,0XAF, 0XB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0XBB,0XBC,0XBD,0XBE,0XBF, 0XC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0XCB,0XCC,0XCD,0XCE,0XCF, 0XD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0XDB,0XDC,0XDD,0XDE,0XDF, 0XE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0XEB,0XEC,0XED,0XEE,0XEF, 0XF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0XFB,0XFC,0XFD,0XFE,0XFF, }; void main(void) { unsigned int i=0,j; unsigned long const Lenth=512; //数据块长度 SD_Init(); //SD 卡初始化 SD_Block_W( Test_1, Lenth*100 , Lenth ); //往地址 51200 处写测试数组 1 SD_Block_W( Test_2, Lenth*100+512, Lenth ); //往地址(51200+512)处写测试数组 2 DATA=SD_Block_R( Lenth*100, Lenth ); //从地址 51200 处读测试数组 1,存于 DATA 中 // DATA=SD_Block_R( Lenth*100+512, Lenth ); //从地址(51200+512)处读测试数组 2,存于 DATA 中 while(1) { for(i=0;i<512;i++)//STC89C52RC 单片机 256 个以后的数据都为 0xFF(内存溢出,数 { //字重影表明单片机正在试图用 P0,P2 口输出地址并读外部 RAM 数据 for(j=0;j<150;j++) Display(DATA[i]); //循环显示数组中的元素 } } } /**************************************** * 显示函数 *****************************************/ void Display(unsigned char Num) { unsigned char First_Bit, Second_Bit, i; First_Bit =Num%16; //取出 16 进制低位 Second_Bit=Num/16; //取出 16 进制高位 P0=0x00; //清数码管显示 P2=LED_Bit[0]; Maplead MCU Development Board http://shop63914145.taobao.com 155 P0=LED_Seg[First_Bit]; //显示 16 进制低位 for(i=0;i<200;i++); P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[Second_Bit]; //显示 16 进制高位 for(i=0;i<200;i++); P0=0x00; } /********************************* * SPI写函数 **********************************/ void SPI_W(unsigned char Data) { unsigned char i; for(i=0;i<8;i++) { Data<<=1; //最高位移入 CY 位中 CLK =0; DI =CY; CLK =1; } DI=1; } /********************************* * SPI读函数 *********************************/ unsigned char SPI_R(void) { unsigned char Data,i; DO=1; //将 DO 口设置为输入状态(对单片机而言是输入口) for(i=0;i<8;i++) { Data <<=1; CLK =0; CLK =1; Data|=DO; } return Data; } /********************************* * 读 SD 卡回应 *********************************/ unsigned char SD_Response() { Maplead MCU Development Board http://shop63914145.taobao.com 156 unsigned char i,Response; for(i=0;i<10;i++) { Response = SPI_R(); if(Response==0x00) break; if(Response==0x01) break; } return Response; } /********************************* * 向 SD 卡写命令 *********************************/ void SD_Cmd(unsigned char Cmd, unsigned long Argument, unsigned char CRC) { unsigned char arg[4]; arg[0]=( unsigned char) Argument; arg[1]=( unsigned char)(Argument>>8); arg[2]=( unsigned char)(Argument>>16); arg[3]=( unsigned char)(Argument>>24); SPI_W(Cmd|0x40); //SD 命令为:(命令号|0x40) SPI_W(arg[3]); SPI_W(arg[2]); SPI_W(arg[1]); SPI_W(arg[0]); SPI_W(CRC); } /********************************* * SD 卡初始化 *********************************/ unsigned char SD_Init(void) { unsigned int delay=0, trials=0; unsigned char i; unsigned char Response=0xFF; CS=1; for(i=0;i<10;i++) SPI_W(0xFF); //上电后给 74 个以上的时钟脉冲 CS=0; SD_Cmd(0x00,0,0x95); //CMD0:复位 SD 卡,CRC 码固定为 0x95 i=0; while(SD_Response()!=0x01) //等待卡回应信号 0x01 { i++; if(i>=100) return 0; //失败返回 0 } Maplead MCU Development Board http://shop63914145.taobao.com 157 CS=1; SPI_W(0xff); //关片选后写 8 个空脉冲,SD 卡复位完毕 i=0; CS=0; while(Response!=0x00) //循环等待初始化成功回应,若成功回应信号为 0x00 { SD_Cmd(0x01,0,0xff); //CMD1:将 SD 卡置为 SPI 模式,无需 CRC 校验,填入 0xFF Response=SD_Response(); i++; if(i>100) //尝试 100 次 return 0; //失败返回 0 } CS=1; SPI_W(0xff); //给 8 个空脉冲 return 1; //成功返回 1 } /********************************* * SD 卡数据块写入 *********************************/ unsigned char SD_Block_W(unsigned char *Block, unsigned long address, unsigned int len) { unsigned int i; unsigned char Response_Write; P1=0xff; CS=0; SD_Cmd(0x18,address,0xFF); //CMD18:块写入命令;address 为要写入块的地址(512 整数倍) while(SD_Response()!=0x00); //循环等待命令回应 0x00 for(i=0;i<10;i++) SPI_W(0xFF); //写入一定量的空脉冲 SPI_W(0xFE); //0xFE 为块写入的头,后面紧跟 512 字节的块数据+2 字节的 CRC 码(0xFF,0xFF) for(i=0;i Maplead MCU Development Board http://shop63914145.taobao.com 162 #include sbit SCL = P1^0; //定义 SCL 引脚 sbit SDA = P1^1; //定义 SDA 引脚 /***************************************** * 启动 I2C 总线 ******************************************/ void I2C_Start(void) { SDA=1; SCL=1; _nop_(); //延时 1us SDA=0; //SDA 低电平跳变启动 I2C 总线 _nop_();_nop_(); SCL=0; //拉低时钟,准备传输数据 _nop_(); SDA=1; //释放数据线 } /***************************************** * 关闭 I2C 总线 ******************************************/ void I2C_Stop(void) { SDA=0; SCL=1; _nop_(); SDA=1; //SDA 高电平跳变关闭 I2C 总线 _nop_();_nop_(); } /**************************************** * 发送一个字节 *****************************************/ void Byte_Send(unsigned char Data) { unsigned char i; for(i=0;i<8;i++) { SCL=0; _nop_(); Data<<=1; //数据左移一位,将数据的最高位移入 PSW 的 CY 位,共移 8 次,即一个字节 SDA=CY; //CY 位送到数据线上 SCL=1; _nop_();_nop_(); } SCL=0; //拉低时钟以便改写数据端口 (时钟线为 1 时,数据线的改变会启动或关闭 I2C 总线) _nop_(); SDA=1; //释放数据线 } Maplead MCU Development Board http://shop63914145.taobao.com 163 /**************************************** * 接收一个字节 *****************************************/ unsigned char Byte_Recv(void) { unsigned char i,Data=0; SCL=0; //拉低时钟以便改写数据端口 _nop_(); SDA=1; //写 1 到数据端口,使该端口为读状态,同时释放数据线 for(i=0;i<8;i++) { SCL=0; _nop_();_nop_(); SCL=1; Data<<=1; //将变量 Data 右移一位,以便接收新一位 Data|=SDA; //将 SDA 位数据存入 Data 的最低位,也可以用 Data+=SDA; } SCL=0; return(Data); } /**************************************** * 读取从器件应答 *****************************************/ bit Device_ACK(void) { bit i; SCL=0; _nop_(); SDA=1; //释放数据线,并置该端口为读状态 _nop_(); SCL=1; _nop_(); i=SDA; //读数据线 _nop_();_nop_(); SCL=0; if(i) //如果应答数据为 0,返回成功标志,否则返回失败标志 return(0); else return(1); } /***************************************** * 主器件应答 ******************************************/ void Master_ACK(void) { SCL=0; _nop_(); Maplead MCU Development Board http://shop63914145.taobao.com 164 SDA=0; //应答 SCL=1; _nop_();_nop_(); SCL=0; _nop_(); SDA=1; //释放数据线 } /***************************************** * 主器件不应答 ******************************************/ void Master_NA(void) { SCL=0; _nop_(); SDA=1; _nop_(); SCL=1; _nop_();_nop_(); SCL=0; } Maplead MCU Development Board http://shop63914145.taobao.com 165 23. AT24C02 芯片的 I2C 总线读写 2K(256×8)AT24C02 E2PEOM AT24C02 是 ATMEL 公司生产的 2K bit(256Bytes)E2PROM 芯片,该芯片 采用 I2C 总线设计,极大的减少了硬件连线的复杂度。其主要性能指标: „ 拥有一个写保护引脚,防止误操作对中数据造成的破坏。 „ 拥有低电压版本与标准电压版本。2.7V(2.7V~5.5V),1.8V(1.8V~5.5V)。 „ I2C 总线设计。 „ 最高可达 100KHz(1.8V,2.5V,2.7V)与 400KHz(5V)的同步时钟频率。 „ 数据写入时间最大 10ms。 „ 拥有 100 万次的写入周期,100 年的数据保存时间。 AT24C02 的引脚定义 图 23-1 AT24C02 引脚定义 表 23-1 AT24C02 引脚定义 引脚定义 说明 1. A0,A1,A2 器件地址设定引脚。 2. GND 电源地。 3. SDA 数据口。 4. SCL 同步时钟口。 5. WP 写保护口。 6. VCC 电源。 A0,A1,A2 口为器件地址设定口,通过对这 3 个口分别接入高电平或低电平 而区别不同的 AT24C02 器件。3 位口最多可编址 8 个,因此一条 I2C 总线上最多 可连接 8 个 AT24C02 器件。 SDA 为器件的数据输入口,在同步时钟 SCL 的配合下,数据从该口进行串 行读写操作。 Maplead MCU Development Board http://shop63914145.taobao.com 166 WP 口为写保护口,当该口接低电平时,可以对整个 AT24C02 器件的 256 个字节进行读写操作。当 WP 口接高电平后,器件前 128 个地址的数据被保护, 只能读,不可写入,后 128 个字节数据可进行读写操作。 AT24C02 的从器件地址 AT24C02 的读写操作遵循 I2C 总线协议。I2C 总线启动后需先提供欲操作器 件的器件地址,AT24C02 的器件地址结构如图 23-2 所示。器件地址的高 4 位为 固定值,都为 1010,低 4 位由两部分组成,分别为器件地址设定位与读/写操作 位。 假如我们将 AT24C02 的 A2,A1,A0 口分别接为低电平、低电平、高电平,那 么其对应的逻辑状态分别为“1”,“0”,“0”,我们对该器件进行写操作,那么相 应的器件地址字节就应该为:1010, 001, 0B,对应的 16 进制数为 0xA2。 图 23-2 AT24C02 的器件地址定义 AT24C02 的字写入 向 AT24C02 的指定地址写入一个字节,在完成 I2C 总线启动及器件寻址后, 应先给出字节所对应的地址,待器件应答后,再写入数据。当写入数据结束后, AT24C02 会给出一个应答信号,这时候单片机应停止 I2C 总线,以使 AT24C02 启动内部写时钟,将数据写入非易失存储器中。在 AT24C02 启动内部时钟后, 器件对任何输入信号都不做响应,直至数据写入完成为止。 图 23-3 AT24C02 的字写入 AT24C02 的页写入 AT24C02 的内部 256 个字节的空间分为 32 个页空间,每个页空间有 8 个字 节。对 AT24C02 的页写入起始过程与字节写入相同,但是在写完一个字节后, Maplead MCU Development Board http://shop63914145.taobao.com 167 不停止 I2C 总线,而是再连续写入最多不超过 7 个字节的数据。在每个数据写入 后器件都会有一个应答信号,字节地址的低 3 位也将随着字节的写入自增 1,将 写入地址增 1。在传送完多个数据,AT24C02 应答后,单片机发出停止 I2C 总线 信号,这时 AT24C02 进入内部写时钟周期,直至所有数据都写入非易失数据存 储器。 当写入数据的地址超过每个页的最后地址后,数据将会从该页的第一个地址 写入数据而将原来数据覆盖。当一次传送的字节数超过 8 个后,多出的数据将会 覆盖本次传输的数据,覆盖顺序从第一个字节开始依次递增。 图 23-4 AT24C02 的页写入 读取 AT24C02 当前地址数据 在每次读写操作完后,AT24C02 的地址寄存器将会增 1 并且保持而不丢失。 在上一次读写完成后,继续进行读操作,AT24C02 将会给出上次操作地址的下 一个地址的数据。数据输出后,单片机不做应答,然后结束 I2C 总线操作。 图 23-5 AT24C02 读当前地址数据 读取 AT24C02 随机地址数据 Maplead MCU Development Board http://shop63914145.taobao.com 168 图 23-6 AT24C02 读随机地址数据 要对 AT24C02 的数据进行随机读取,需先进行一段“伪写入”操作,即,启 动 I2C 总线后,设定 I2C 总线为写状态,以写入欲读取数据的地址字节。AT24C02 器件应答后,单片机再执行重启总线操作,即给出一个 I2C 总线启动操作,然后 写入器件地址及置 I2C 总线为读操作,AT24C02 器件应答后将会给出欲读取的数 据,待数据读取完毕后,单片机不做应答,最后由单片机结束 I2C 总线的操作。 连续读取 AT24C02 数据 AT24C02 能够连续地读取多个数据。AT24C02 的连续读分为随机读和当前 地址读两种。 当单片机对 AT24C02 的当前地址读完一个字节或者读取完一个随机地址的 数据后给 AT24C02 器件一个应答信号,器件将会连续地输出当前地址的下一个 地址的数据,直至单片机不做应答并结束 I2C 总线。 单片机不停止 I2C 总线的情况下,AT24C02 的地址会一直自增 1,并且把对 应地址的数据输出给单片机,如果 AT24C02 的地址增加到 255,那么下一个地 址将从 0 开始,直至单片机不做应答并给出停止信号。 图 23-7 AT24C02 连续读数据 AT24C02 实验电路连接实物图 图 23-8 AT24C02 拨码开关设置 Maplead MCU Development Board http://shop63914145.taobao.com 169 拨码开关按照图中所示进行设定。 可以改变配套程序给定的地址码,从而改变拨码开关的设定。 AT24C02 读写演示程序 /****************************************************************************** * 文件:I2C_AT24C02.c * 说明: * (1)晶振 12Mhz 调试通过。 * (2)AT24C02 驱动程序。 * (3)执行此程序前要将上一节的 I2C 总线函数包含进来。 * (4)AT24C02 的拨码开关的 A0、A1、A2 要全部拨到右侧的 ON 位置。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #define Device_Add 0xAE//器件地址:1010(器件预设地址), 1(A2) 1(A1) 1(A0)(三位设定地址), 0(读写标志位) #define EEprom_R 0x01 //读 #define EEprom_W 0x00 //写 /**************************************************** 字写入 ****************************************************/ bit AT24C02_Byte_W(unsigned char Data_Add, unsigned char Data) { unsigned int i; bit Flag; I2C_Start(); //启动 I2C Byte_Send(Device_Add | EEprom_W); //送器件地址,并置读写标志位为写 Device_ACK(); //器件应答 Byte_Send(Data_Add); //送欲存储数据的地址 Device_ACK(); //器件应答 Byte_Send(Data); //存数据 for(i=0;i<600;i++); //延时,EEprom 保存数据 Flag=Device_ACK(); //器件应答 I2C_Stop(); //停止 I2C for(i=0;i<600;i++); if(Flag) return 1; else return 0; } /**************************************************** * 页写入 * 一次页写入 8 个字节的数据。 *****************************************************/ bit AT24C02_Page_W(unsigned char Data_Add, unsigned char *Data) Maplead MCU Development Board http://shop63914145.taobao.com 170 { unsigned char i; unsigned int j; bit Flag=1; I2C_Start(); Byte_Send(Device_Add | EEprom_W); //送器件地址,并置读写标志位为写 Device_ACK(); Byte_Send(Data_Add); Device_ACK(); for(i=0;i<8;i++) { Byte_Send( *Data ); for(j=0;j<600;j++); //EEprom 保存数据 Flag &= Device_ACK(); //器件应答 Data++; //数值地址增 1 } I2C_Stop(); for(j=0;j<600;j++); if(Flag) return 1; else return 0; } /**************************************************** * 读当前地址数据 *****************************************************/ unsigned char AT24C02_CurrentAdd_R(void) { unsigned char Data; I2C_Start(); Byte_Send(Device_Add | EEprom_R); //写入器件地址,并置读写位为读 Device_ACK(); Data=Byte_Recv(); Master_NA(); I2C_Stop(); return Data; } /**************************************************** * 随机读 ****************************************************/ unsigned char AT24C02_Random_R(unsigned char Data_Add) { unsigned char Data; /****************************************** * 先执行一次伪写入,将数据地址写入 EEPROM *******************************************/ Maplead MCU Development Board http://shop63914145.taobao.com 171 I2C_Start(); Byte_Send(Device_Add | EEprom_W); Device_ACK(); Byte_Send(Data_Add); Device_ACK(); /***************************************** * 读当前地址数据(前面过程中写入的地址) ******************************************/ Data=AT24C02_CurrentAdd_R(); return Data; } Maplead MCU Development Board http://shop63914145.taobao.com 172 24. AT24C04 芯片的 I2C 总线读写 4K(512×8)AT24C04 E2PEOM AT24C04 是 ATMEL 公司生产的 4K bit(512Bytes)E2PROM 芯片,该芯片 采用 I2C 总线设计,主要性能指标与 AT24C02 类似,不同点为: „ 容量为 AT24C02 的两倍,分为两部分存储空间,每部分 256bytes。 „ 有 2 个器件地址选择脚,一个 I2C 总线最多能够挂接 4 个 AT24C04 器件。 „ 32 页,每页 16 字节,每次可连续写入 16 字节数据。 „ WP 引脚为高电平时,AT24C04 的 0~255 地址空间的数据被写保护。 „ 需要 9 位的地址进行数据寻址。 AT24C04 的引脚定义 图 24-1 AT24C02 引脚定义 表 24-1 AT24C02 引脚定义 引脚定义 说明 1. A0 空引脚。 2. A1,A2 器件地址设定引脚。 3. GND 电源地。 4. SDA 数据口。 5. SCL 同步时钟口。 6. WP 写保护口。 7. VCC 电源。 A0 为空引脚,A1,A2 口为器件地址设定口,通过 A1,A2 口来设定 AT24C04 的器件地址 WP 口接低电平时,可以对整个 AT24C04 器件的 512 个字节进行读写操作。 当 WP 口接高电平后,器件前 256 个地址的数据被保护,只能读,不可写入,后 256 个字节数据可进行读写操作。 Maplead MCU Development Board http://shop63914145.taobao.com 173 AT24C04 的从器件寻址 图 24-2 AT24C04 的器件及数据空间地址 AT24C04 的器件地址由两个引脚决定,分别为 A1,A2 引脚。 AT24C04 的数据空间由 P0 位决定,如图 24-2 所示,当 P0 为“0”时,将对 AT24C04 的 0~255 空间的数据进行操作;当当 P0 为“1”时,将对 AT24C04 的 256~511 空间的数据进行操作。 AT24C04 的读写操作 对 AT24C04 的读写操作与 AT24C02 的读写操作完全相同。不同的是, AT24C04 分为 2 个数据区,用 P0 位加以区别,当 P0=0 时,操作的是 0~255 地 址单元的数据;当 P0=1 时,操作的是 256~511 地址单元的数据。 图 24-3 AT24C04 的拨码开关设置 AT24C04 的拨码开关设置只有 2 位(A1、A2),例程中应按图 24-3 设置。 AT24C04 读写演示程序 /****************************************************************************** * 说明: * (1)晶振 12Mhz 调试通过 * (2)AT24C04 驱动程序。 * (3)执行此程序前要将上一节的 I2C 总线函数包含进来。 * (4)AT24C04 的拨码开关 A1、A2 位要全部拨至左边。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ Maplead MCU Development Board http://shop63914145.taobao.com 174 #include #define Device_Add 0xA0//器件地址:1010(器件预设地址), 0(A2) 0(A1)(两位设定地址) 0(页选择位), 0(读写标志位) #define EEprom_R 0x01 //读 #define EEprom_W 0x00 //写 /*********************************************** * 字写入 * Page 为 AT24C04 的页选择位,用来选择 EEPROM * 页 0 的 256byte 或者页 1 的 256byte。 *************************************************/ bit AT24C04_Byte_W(unsigned char Page, unsigned char Data_Add, unsigned char Data) { unsigned int i; bit Flag; I2C_Start(); //启动 I2C Byte_Send( Device_Add | Page | EEprom_W ); //送器件地址,页选择位,并置读写标志位为写 Device_ACK(); //器件应答 Byte_Send(Data_Add); //送欲存储数据的地址 Device_ACK(); //器件应答 Byte_Send(Data); //存数据 for(i=0;i<1000;i++); //延时,EEprom 保存数据 Flag=Device_ACK(); //器件应答 I2C_Stop(); //停止 I2C for(i=0;i<1000;i++); if(Flag) return 1; else return 0; } /*********************************************** * 页写入 * * (1)一次页写入 8 个字节的数据 (数据手册上说 * AT24C04 可以一次页写入 16 个数据,实测只能一次 * 写入 8 个,如果超过 8 个数据,EEPROM 地址指针将 * 翻转,前面的数据将被覆盖)。 * (2)如果连续写入数据的地址超过 256,地址将从 0 地址 * 重新开始,从 0 地址开始的数据将被新数据覆盖,原数 * 据丢失。 *************************************************/ bit AT24C04_Page_W(unsigned char Page, unsigned char Data_Add, unsigned char *Data) { unsigned char i; unsigned int j; bit Flag=1; I2C_Start(); Byte_Send( Device_Add | Page | EEprom_W );//送器件地址,页选择位,并置读写标志位为写 Device_ACK(); Byte_Send(Data_Add); Maplead MCU Development Board http://shop63914145.taobao.com 175 Device_ACK(); for(i=0;i<8;i++) { Byte_Send( *Data ); for(j=0;j<1000;j++); //EEprom 保存数据 Flag &= Device_ACK(); //器件应答 Data++; //数值地址增 1 } I2C_Stop(); for(j=0;j<1000;j++); if(Flag) return 1; else return 0; } /********************************************** * 读当前地址数据 ***********************************************/ unsigned char AT24C04_CurrentAdd_R(unsigned char Page) { unsigned char Data; I2C_Start(); Byte_Send( Device_Add | Page | EEprom_R );//写入器件地址,页选择位,并置读写位为读 Device_ACK(); Data=Byte_Recv(); Master_NA(); I2C_Stop(); return Data; } /************************************************* * 随机读 **************************************************/ unsigned char AT24C04_Random_R(unsigned char Page, unsigned char Data_Add ) { unsigned char Data; /****************************************** * 先执行一次伪写入,将数据地址写入 EEPROM *******************************************/ I2C_Start(); Byte_Send( Device_Add | Page | EEprom_W ); //写入器件地址,页选择位,并置读写位为读 Device_ACK(); Byte_Send(Data_Add); Device_ACK(); /***************************************** * 读当前地址数据(前面过程中写入的地址) ******************************************/ Data=AT24C04_CurrentAdd_R(Page); return Data; } Maplead MCU Development Board http://shop63914145.taobao.com 176 25. I2C 总线温度传感器 LM75A LM75A 温度传感器 LM75A 是 PHILIPS 公司生产的 I2C 接口温度传感器芯片,其主要特点为: „ 电压范围为 2.8V~5.5V。 „ 有 3 个器件地址选择脚,一个 I2C 总线最多能够挂接 8 个 LM75A 温度传感 器。 „ 测温范围为-55℃~125℃。 „ 最低温度分辨率为 0.125℃。 „ 测温精度为: -25℃~100℃温度范围内精度为±2℃; -55℃~125℃温度范围内精度为±3℃; „ WP 引脚为高电平时,AT24C04 的 0~255 地址空间的数据被写保护。 LM75A 的引脚定义 图 25-1 AT24C02 引脚定义 表 25-1 AT24C02 引脚定义 引脚定义 说明 1. SDA 数据口。 2. SCL 同步时钟口。 3. OS 过温 4. GND 电源地。 5. A2 器件地址设定引脚 A2。 6. A1 器件地址设定引脚 A1。 7. A0 器件地址设定引脚 A0。 8. VCC 电源。 LM75A 的从器件寻址 Maplead MCU Development Board http://shop63914145.taobao.com 177 图 25-2 LM75A 的器件地址 LM75A 的器件地址由 3 个引脚决定,分别为 A0, A1, A2 引脚。其高 4 位固 定地址为 1001B,所以,一个 I2C 总线最多能够挂接 8 个 LM75A 温度传感器。 LM75A 的内部寄存器 LM75A 内部共有 5 组寄存器,分别是:指针寄存器(Pointer Register)、温 度寄存器(Temp)、配置寄存器(Conf)、滞温寄存器(Thyst)、超温寄存器(Tos)。 指针寄存器: 指针寄存器是一个 8 位寄存器,该寄存器用来指定将要操作的其他 4 个寄存 器。内部的高 6 位恒为 0,最低 2 位(B1, B0)可以人为指定,其指定值及其所 指向的寄存器对应关系见表 25-2。 例如,当我们要读取温度寄存器的时候,我们先设定指针寄存器的值为 0000 0000B,则接下来读到的数据便来自于温度寄存器。但指针寄存器上电后的 初始值就为 0000 0000B,所以,上电后要读取温度值可不设定指针寄存器而直 接读取数据,因为指针寄存器默认所指向的就是温度寄存器。只有在指针寄存器 被改写以后,才需要对指针寄存器进行重新设定。 表 25-2 指针寄存器的值及其所指向的寄存器 B1 B0 指向的寄存器 0 0 温度寄存器(Temp) 0 1 配置寄存器(Conf) 1 0 滞温寄存器(Thyst) 1 1 超温寄存器(Tos) 温度寄存器: 温度寄存器由 2 个 8 位寄存器组成,该寄存器内存放有 LM75A 所测定的温 度值。温度寄存器内部数据的存储格式见图 25-3。 温度寄存器的高 8 位存有温度值的 D3~D10 位,低 8 位存有温度值的 D0~ D2 位。 高 8 位寄存器内存储的数据与摄氏温度整数值一一对应,当该寄存器的值每 Maplead MCU Development Board http://shop63914145.taobao.com 178 增加(或减少)1,则对应的摄氏温度值也增加(或减少)1℃。 低 8 位寄存器的 D0~D2 位为温度值的小数位,每增加(或减少)1 表示摄 氏温度值增加(或减少)0.125℃。示例见表 25-3。 温度值的负值是用补码来表示的,负值的范围为-0.125℃~-55.000℃。示例 见表 25-3。因此,在进行程序设计的时候,存储温度的变量要设置成有符号类型, 而不要设计成 unsigned 类型。 LM75A 的温度转换时间为 100ms,因此读取温度时间间隔应大于 100ms。 图 25-3 温度寄存器内部的数据存储结构 表 25-3 温度寄存器内部的数据及所对应的温度值 配置寄存器: 配置寄存器是一个 8 位的寄存器,其中的低 5 位可以用来对 LM75A 进行各 种模式的配置。 表 25-4 配置寄存器内部的各位及其所对应的功能 位 名称 读/写 初始值 说明 B7-B5 保留 读/写 000 厂家保留 B4-B3 OS 误差队列 读/写 00 取值 0,1,2,3 对应误差队列的 1,2,4,6 B2 OS 引脚极性 读/写 0 超温 OS 脚:1-输出高电平;0-输出低电平 B1 OS 中断/比较 读/写 0 1-OS 中断模式;0-OS 比较模式 B0 停止运行位 读/写 0 1-器件停止运行;0-器件正常运行 Maplead MCU Development Board http://shop63914145.taobao.com 179 B7~B5 位为厂家的保留位,操作中应予以忽略。 B4~B3 位为误差队列设定位。当这两位的值为 0,1,2,3 时,其所对应的 误差队列长度为 1,2,4,6。误差队列可理解为:当器件连续 n 次采样温度都 超过设定的 Tos 温度值之后,OS 脚输出超温信号。 B2 位为 OS 引脚极性设定位。当该位设定为 1 时,超温后 OS 脚输出高电平, 当该位设定为 0 时,超温后 OS 脚输出低电平。 B1 位为中断/比较设定位。当该位为 1 时,超温警报采用中断模式运行,当 该位为 0 时,超温警报采用比较模式运行。中断模式与比较模式的不同之处见图 25-4。当测定的温度超过了设定的 Tos 值后,并且比较的次数满足误差队列,则 OS 脚输出中断信号。在中断模式下,对任意寄存器的读操作或置器件停止运行 都将重置 OS 引脚的中断信号(即停止输出中断信号)。在比较模式下,器件 OS 引脚会一直输出中断信号,直至所测试的温度低于设定的 Thyst 以后,OS 引脚 电平才会被重置。 图 25-4 超温警报的中断与比较模式 *中断输出被重置,对任意寄存器的读操作或设置器件停止运动都将中断重置。 Maplead MCU Development Board http://shop63914145.taobao.com 180 B0 为器件停止运行位,当该位置位后器件即进入停止状态,但此时仍然可 以通过数据线对器件进行任意设定。当该位清零后,器件即恢复正常运行状态。 超温寄存器: 超温寄存器存储有某一温度值,器件在正常的运行过程中会不断地将采集到 的温度与此寄存器存储的值进行比较,当采集到的温度滞超过此设定温度,并且 误差队列的次数也满足的情况下,器件会通过 OS 引脚对外输出中断信号。 图 25-5 超温寄存器内部的数据存储结构 超温寄存器的有效数据位为 10 位,高 8 位寄存器存储了温度设定值的整数 部分,低 8 位的最高位(B7)存储了温度设定值的小数部分,小数部分的每个 单位代表温度值为 0.5℃。 超温寄存器的温度设定值及其所对应的温度值见表 25-6。 表 25-6 超温与滞温寄存器内部的数据及所对应的温度值 滞温寄存器: 滞温寄存器的功能是给器件提供一个与超温寄存器温度值的温度差,以便在 实际的温度控制中留有一个缓冲的余地。 图 25-6 滞温寄存器内部的数据存储结构 Maplead MCU Development Board http://shop63914145.taobao.com 181 例如,在某系统中,我们设定 LM75A 的 Tos=70℃,Thyst=65℃,当器件 检测到系统的温度值超过了设定的上限值 70℃(Tos 值),并且误差队列也满足 后,器件通过 OS 脚输出中断,微控制器在收到中断信号后启动风扇进行散热, 直至温度降低至 65℃以下,满足误差队列次数后,LM75A 才停止输出中断信号, 则微控制器关闭风扇,从而保证了系统的温度运行在适当范围内。 滞温寄存器内部的数据存储结构跟超温寄存器内部存储结构是相同的,其每 一位所对应的值也都是相同的。 值得注意的是,Thyst 寄存器的值一定要适当的小于 Tos 寄存器的值。 LM75A 的读写操作 对 LM75A 的读写操作采用标准的 I2C 总线操作方式,数据传输的开始、停 止、器件的应答均符合 I2C 总线的要求。在对器件进行的读写过程中,数据传输 始终是高位在前,低位在后。 不设定指针寄存器读取温度值: 当器件上电后,由于指针寄存器的初始值为 0x00,其指向的寄存器为温度 寄存器,所以上电后可以不用设定指针寄存器而直接对温度寄存器进行读操作。 如图 25-7 所示,器件启动并给器件地址后,指定本次操作为读操作,LM75A 器 件对微控制器进行一次应答,接着器件会输出 16 位温度寄存器值的高 8 位,微 控制器应答,器件输出 16 位温度寄存器值的低 8 位,微控制器不应答,最后微 控制器给一个结束信号,则本次读取操作结束。 图 25-7 读取温度值(不设定指针寄存器) 读写配置寄存器值: 对配置寄存器的读写操作需要先配置指针寄存器,以使下一步读写的对象为 指针指定的寄存器。 写操作可以一次进行到低,但是读操作需要先写(写指针寄存器)重启动后 再读。因为写入指针寄存器后,指针寄存器的内容在断电或重新写入之前不会改 Maplead MCU Development Board http://shop63914145.taobao.com 182 变。 写配置寄存器值流程:I2C 总线启动后,微控制器送器件地址并指定为写操 作,器件应答,微控制器写入地址指针值 0x01(指向配置寄存器),器件应答, 微控制器写入配置寄存器中相应的参数值,器件应答,微控制器发出结束总线传 输信号,传输结束。 图 25-8 写配置寄存器值 读配置寄存器值流程:I2C 总线启动后,微控制器送器件地址并指定为写操 作,器件应答,微控制器写入地址指针值 0x01(指向配置寄存器),器件应答, 微控制器重新启动 I2C 总线传输,微控制器送器件地址并指定为读操作,器件应 答,器件输出配置寄存器值,微控制器不应答,微控制器发出结束总线传输信号, 传输结束。 图 25-8 读配置寄存器值 设定指针寄存器读写温度值(Temp 只), Tos 与 Thyst 可读写): 设定指针寄存器写 Tos 或 Thyst 寄存器温度值流程:I2C 总线启动后,微控 制器送器件地址并指定为写操作,器件应答,微控制器写入地址指针值(指向 Maplead MCU Development Board http://shop63914145.taobao.com 183 Tos 或 Thyst 寄存器),器件应答,微控制器写入高 8 位温度值(高位在前),器 件应答,微控制器写入低 8 位温度值(高位在前),器件应答,微控制器发出结 束总线传输信号,传输结束。 图 25-9 设定指针寄存器写 Tos 或 Thyst 寄存器 设定指针寄存器读 Temp、Tos 或 Thyst 寄存器温度值流程:I2C 总线启动后, 微控制器送器件地址并指定为写操作,器件应答,微控制器写入地址指针值(指 向 Temp、Tos 或 Thyst 寄存器),器件应答,微控制器重新启动 I2C 总线,微控 制器送器件地址并指定为读操作,器件应答,器件输出高 8 位温度值(高位在前), 微控制器应答,器件输出低 8 位温度值(高位在前),微控制器不应答,微控制 器发出结束总线传输信号,传输结束。 图 25-10 设定指针寄存器读 Temp、Tos 或 Thyst 寄存器 Maplead MCU Development Board http://shop63914145.taobao.com 184 图 25-11 LM75A 的拨码开关设置 LM75A 的拨码开关设置应按图 25-11 设置。 LM75A 读取温度值演示程序 例程 25-1 LM75A 读取温度值 /****************************************************************************** * 说明: * (1)晶振 12Mhz 调试通过 * (2)器件地址 1001 000,LM75A 的拨码开关 A0、A1、A2 要全部拨至左边。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #include #define Dev_ADD 0x90 //器件地址,1001(硬件地址),0(A2) 0(A1) 0(A0) (可设定地址), 0(读写标志) #define I2C_Read 0x01 //读操作标志位 #define I2C_Write 0x00 //写操作标志位 sbit SCL = P1^0; sbit SDA = P1^1; unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管段码 0~9 unsigned char code LED_Dot=0x80; //小数点 unsigned char code LED_Bit[]={0,1,2,3,4,5,6,7}; //数码管位码 void I2C_Start(void); //I2C 设备启动 void I2C_Stop(void); //I2C 设备停止 void Byte_Send(unsigned char); //发送一个字节 unsigned char Byte_Recv(void); //接收一个字节 bit Device_ACK(void); //I2C 设备应答 void Master_ACK(void); //单片机应答 void Master_NA(void); //单片机不应答 int Read_Temp(void); //读温度值 Maplead MCU Development Board http://shop63914145.taobao.com 185 unsigned char * Calculate(int); //计算温度,并将计算出来的数据分解成各个位显示的数值 void Display(int); //在数码管上显示数据 void main(void) { unsigned int i; int Temp=0; while(1) { Temp=Read_Temp(); //读温度 Temp/=32; //右移 5 位 for(i=0;i<50;i++) Display(Temp); } } /************************************* * 启动 I2C 总线 *************************************/ void I2C_Start(void) { SDA=1; SCL=1; _nop_(); //延时 1us SDA=0; //SDA 低电平跳变启动 I2C 总线 _nop_();_nop_(); SCL=0; //拉低时钟,准备传输数据 _nop_(); SDA=1; //释放数据线 } /************************************** * 关闭 I2C 总线 **************************************/ void I2C_Stop(void) { SDA=0; SCL=1; _nop_(); SDA=1; //SDA 高电平跳变关闭 I2C 总线 _nop_();_nop_(); } /*************************************** * 发送一个字节 ****************************************/ void Byte_Send(unsigned char Data) { unsigned char i; for(i=0;i<8;i++) { SCL=0; Maplead MCU Development Board http://shop63914145.taobao.com 186 _nop_(); Data<<=1; //数据左移一位,将数据的最高位移入 PSW 的 CY 位,共移 8 次,即一个字节 SDA=CY; //CY 位送到数据线上 SCL=1; _nop_();_nop_(); } SCL=0; //拉低时钟以便改写数据端口 (时钟线为 1 时,数据线的改变会启动或关闭 I2C 总线) _nop_(); SDA=1; //释放数据线 } /****************************************** * 接收一个字节 ******************************************/ unsigned char Byte_Recv(void) { unsigned char i,Data=0; SCL=0; //拉低时钟以便改写数据端口 _nop_(); SDA=1; //写 1 到数据端口,使该端口为读状态,同时释放数据线 for(i=0;i<8;i++) { SCL=0; _nop_();_nop_(); SCL=1; Data<<=1; //将变量 Data 右移一位,以便接收新一位 Data|=SDA; //将 SDA 位数据存入 Data 的最低位,也可以用 Data+=SDA; } SCL=0; return(Data); } /********************************************* * 器件应答 *********************************************/ bit Device_ACK(void) { bit i; SCL=0; _nop_(); SDA=1; //释放数据线,并置该端口为读状态 _nop_(); SCL=1; _nop_(); i=SDA; //读数据线 _nop_();_nop_(); Maplead MCU Development Board http://shop63914145.taobao.com 187 SCL=0; if(i) //如果应答数据为 0,返回成功标志,否则返回失败标志 return(0); else return(1); } /********************************************* * 单片机应答 *********************************************/ void Master_ACK(void) { SCL=0; _nop_(); SDA=0; //应答 SCL=1; _nop_();_nop_(); SCL=0; _nop_(); SDA=1; //释放数据线 } /*********************************************** * 单片机不应答 ************************************************/ void Master_NA(void) { SCL=0; _nop_(); SDA=1; _nop_(); SCL=1; _nop_();_nop_(); SCL=0; } /************************************************* * 读温度值 *************************************************/ int Read_Temp(void) { int Temp=0; I2C_Start(); Byte_Send( Dev_ADD | I2C_Read ); //送器件地址并置操作为读操作 Device_ACK(); Temp|=Byte_Recv(); //读高 8 位 Master_ACK(); Temp<<=8; //将读取的 8 位数据移位至 Temp 的高 8 位处 Temp|=Byte_Recv(); //读低 8 位 Master_NA(); I2C_Stop(); return(Temp); Maplead MCU Development Board http://shop63914145.taobao.com 188 } /************************************************* * 显示温度值 *************************************************/ void Display(int Num) { unsigned char BIT[]={0,0,0,0,0,0,0}; //将器件中读出的温度值计算并分解成各个位,存入数组 BIT[] 中 unsigned char i; unsigned long Val; bit Flag_Neg=0; //负数标志 if(Num<0) //如果数值为负数 { Num=-Num; //转换成正数处理 Flag_Neg=1; //负数标志置位 } Val=(INT32U)Num; Val=(INT32U)(Val*125); //计算出放大了 1000 倍的温度值(本为:Num = Num * 0.125) if(Flag_Neg) //如果数值为负值 { if(Val<10000) //如果数值大于-10 则在数字的十位显示负号 BIT[6]=4; else //如果数值小于-10 则在数字的百位显示负号 BIT[6]=5; } BIT[0]=(INT8U) (Val%10); //取出千分位 BIT[1]=(INT8U) ((Val%100)/10); //百分位 BIT[2]=(INT8U) ((Val%1000)/100); //十分位 BIT[3]=(INT8U) ((Val%10000)/1000); //个位 BIT[4]=(INT8U) ((Val%100000)/10000); //十位 BIT[5]=(INT8U) ((Val%1000000)/100000); //百位 P0=0x00; //清除显示 P2=LED_Bit[0]; P0=LED_Seg[BIT[0]]; //显示千分位 for(i=0;i<255;i++); //延时一小会,增加数码管的亮度 P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[ BIT[1] ]; //显示百分位 for(i=0;i<255;i++); P0=0x00; P2=LED_Bit[2]; P0=LED_Seg[BIT[2]]; //显示十分位 for(i=0;i<255;i++); P0=0x00; Maplead MCU Development Board http://shop63914145.taobao.com 189 P2=LED_Bit[3]; P0=(LED_Seg[BIT[3]]) | (LED_Dot); //显示个位 & 小数点 for(i=0;i<255;i++); P0=0x00; if( BIT[4]|BIT[5] ) //如果十位与百位不同时为零,则显示十位 { P2=LED_Bit[4]; P0=LED_Seg[BIT[4]]; //显示十位 for(i=0;i<255;i++); } P0=0x00; if( BIT[5] ) //如果百位为零,则不显示百位 { P2=LED_Bit[5]; P0=LED_Seg[BIT[5]]; //显示百位 for(i=0;i<255;i++); } P0=0x00; if(Flag_Neg) { P2=LED_Bit[BIT[6]]; //如果为负值显示负号 P0=0x40; for(i=0;i<255;i++); } P0=0x00; } Maplead MCU Development Board http://shop63914145.taobao.com 190 26. 单总线温度传感器 DS18B20 DS18B20 单总线温度传感器 DS18B20 温度传感器为 Dallas 公司生产的全数字式、单总线温度传感器, 该传感器具备以下特点: „ 单根总线数字传输。 „ 12 位分辨率,精度可以达到±0.5℃。 „ 低功耗,可选择寄生工作方式运行。 „ 检测温度范围为-55℃~125℃。 „ 内部具有 64 位光刻 ROM,供多机识别。 DS18B20 的引脚定义 图 26-1 DS18B29 温度传感器引脚 表 26-1 DS18B20 温度传感器引脚说明 引脚 说明 GND 电源地。 DQ 数据输入输出总线。 VDD 电源。 DS19B20 内部存储器 DS18B20 内部共有 9 个 RAM,3 个 E2PROM。 9 个 RAM 的第 0,1RAM 存储单元为温度存储单元,内存储了上一次转换 温度值,0 存储单元存储了转换温度的低 8 位,1 单元存储了转换温度的高 8 位。 第 2,3,4RAM 存储单元为 DS18B20 内部 E2PROM 的镜像。存储在 RAM 中的数据掉电后会丢失,而存储在 E2PROM 中的数据则不会丢失,便于用户长 Maplead MCU Development Board http://shop63914145.taobao.com 191 期存放数据。可以通过特定的指令将这 3 个单元存储的数据写入 E2PROM 中, 也可以通过特定的指令将 E2PROM 中的数据读出至 RAM 中。 第 2,3RAM 单元可以由用户指定存储内容或存储高温/低温警报温度值等。 图 26-2 DS18B20 温度传感器内部存储器组织结构 第 4RAM 单元为配置单元,可通过配置该单元的 R0,R1 两个位对 DS18B20 温度转换的精度进行配置,以满足实际需求。R0,R1 的配置见表 26-2。 图 26-3 配置(Config)单元结构图 表 26-2 R0,R1 对应的温度分辨率配置 R0 R1 温度精度 转换时间 0 0 9 位 93.75ms 0 1 10 位 187.5ms 1 0 11 位 375ms 1 1 12 位 750ms DS19B20 指令 Maplead MCU Development Board http://shop63914145.taobao.com 192 ROM 功能指令: (1) 读 ROM(指令码 0x33) 使单片机读 DS18B20 的 64 位 ROM。只有当总线上只存在一个 DS18B20 的 时候才能使用此命令,如果挂接多只 DS18B20 在通信时将会发生数据冲突。 (2) 匹配芯片(指令码 0x55) 本指令后跟由单片机发出的 64 位序列号,当总线上有多只 DS18B20 时,只 有与序列号相同的芯片才可以做出反应,其它芯片将等待下一次复位。这条指令 适应 DS18B20 的多片挂接。 (3) 跳过 ROM 指令(指令码 0xCC) 本指令使 DS18B20 跳过 ROM 指令,在单个 DS18B20 的情况下,为了节省 时间选用此指令。在多芯片挂接时使用此指令会出现数据冲突。 (4) 搜索 ROM(指令码 0xF0) 芯片初始化后,搜索 ROM 指令允许总线上挂接多芯片时用排除法识别所有 器件的 64 位 ROM。 (5) 警报搜索 在多芯片挂接的情况下,报警芯片搜索指令只对符合温度高于 TH 或小于 TL 报警条件的芯片做出反应。只要芯片不掉电,报警状态将被保持,直到再一 次测得温度什达不到报警条件为止。 RAM 指令: (1) 写 RAM(指令码 0x4E) RAM 中写入数据,随后写入的两个字节的数据将会被存到地址 2(TH)和 地址 3(TL)中。复位信号中止写入过程。 (2) 读 RAM(指令码 0xBE) 从 RAM 中读数据,读地址从地址 0 开始,一直读到地址 9,完成整个 RAM 数据的读出。芯片允许在读过程中用复位信号中止,即可以不读后面不需要的字 节以减少读取时间。 (3) 拷贝 RAM(指令码 0x48) 将 RAM 中的数据存入 EEPROM 中。当单片机发一个读时间隙时,存储未 Maplead MCU Development Board http://shop63914145.taobao.com 193 完成时总线上输出“0”;储存完成时总线将输出“1”。 (4) 温度转换开始(指令码 0x44) 进行新一次温度转换,将转换的温度值放入 RAM 的第 0、1 地址。当单片 机发一个读时间隙,未转换完成时总线上输出“0”,转换完成时总线将输出“1”。 (5) 拷贝 E2PROM(指令码 0xB8) 将 E2PROM 中的数据拷贝到 RAM 中。当单片机发一个读时间隙,未拷贝完 成时总线上输出“0”,拷贝完成时总线将输出“1”。 (6) 读工作方式(指令码 0xB4) 此指令可以获取器件的工作状态,“0”为寄生电源状态,“1”为外部电源状态。 DS18B20 的读写操作 DS18B20 单总线是靠读/写“时间隙”来识别“0”,“1”的。 图 26-4 DS18B20 写时间隙 DS18B20 每个写的“时间隙”必须为 60us,“时间隙”之间的间隔必须大于等 于 1us。 单片机写“0”时间隙是将单总线拉低 60us 来实现的。在时间隙的第 15~60us 范围内,DS18B20 采样数据线。 单片机写“1”时间隙是将单总线拉低 15us,而后将单总线拉高 45us。在时间 隙的第 15~60us 范围内,DS18B20 采样数据线。 单片机读每个时间隙的间隔也必须为 60us,时间隙之间间隔 1us 以上。 单片机读时间隙是单片机将单总线拉低至少 1us,在随后的 15us 时间内单片 机释放总线并读取总线状态,如果总线被拉低,则表示传输数据 0,如果总线为 高电平,则表示传输的数据为 1。 Maplead MCU Development Board http://shop63914145.taobao.com 194 图 26-5 DS18B20 读时间隙 DS18B20 的温度转换过程 操作单个 DS18B20 器件的时候,可以使用跳过 ROM 操作指令,从而可以 节省时间并且跳过 CRC 校验过程。 DS18B20 的启动过程包括 3 个步骤,重置(Reset)、跳过 ROM 指令、启动 温度转换。 重置过程为单片机拉低单总线最少 480us、最大 960us,然后释放总线并等 待 DS18B20 向总线上发出一个低电平的存在脉冲,该脉冲的长度为 60~240us。 DS18B20 发送完存在脉冲后单片机向 DS18B20 写跳过 ROM 指令。 单片机向 DS18B20 写开始温度转换指令,开始温度转换。 等待至少 750ms 以后,单片机读取温度值。 DS18B20 在开发板上的安装 图 26-6 DS18B20 安装图 DS18B20 器件应该按照图 26-6 所示的安装方式,器件的 3 个引脚插入开发 板的插座上,器件的曲面朝上,有字的平面朝向光耦的方向。 Maplead MCU Development Board http://shop63914145.taobao.com 195 提示:如果器件接反会发热,并很快被烧毁。因此,建议安装后,先不要接 通开发板电源,应先用手触碰该器件,上电后如果感觉发热应立即断电并重新连 接! DS18B20 温度转换演示程序 图 26-7 DS18B20 电路连接图 例程 26-1 DS18B20 温度转换 /******************************************************************* * 文件: DS18B20.c * 说明: * (1)晶振 12Mhz 调试通过。 * (2)DS18B20 温度转换。 * 作者:Shenney John ******************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ********************************************************************/ #include #include #define Delay_1us() _nop_() #define Delay_2us() _nop_(); _nop_() #define Delay_4us() Delay_2us(); Delay_2us() #define Delay_5us() Delay_4us(); Delay_1us() #define Delay_8us() Delay_4us(); Delay_4us() #define Delay_10us() Delay_8us(); Delay_2us() #define Delay_15us() Delay_10us(); Delay_5us() unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管段码 0~9 unsigned char code LED_Dot=0x80; //小数点 unsigned char code LED_Bit[]={0,1,2,3,4,5,6,7}; //数码管位码 sbit DIO=P2^3; bit DS18B20_Init(void); void Byte_W(unsigned char); Maplead MCU Development Board http://shop63914145.taobao.com 196 unsigned char Byte_R(void); void Delay(unsigned int); void main(void) { int data Temp; unsigned int data i; while(1) { Temp_Cnvt_Start(); //启动转换 for(i=0;i<80;i++) //显示温度,顺便延时 750ms 以上 Display(Temp); Temp=Temp_R(); //读取温度 } } /******************************************************************** * 启动温度转换函数 ********************************************************************/ void Temp_Cnvt_Start(void) { DS18B20_Init(); //初始化 Byte_W(0xCC); //跳过序列号检查 Byte_W(0x44); //启动温度转换 } /******************************************************************** * 读温度函数 ********************************************************************/ int Temp_R(void) { unsigned char data Temp_L,Temp_H; int data Data=0; DS18B20_Init(); Byte_W(0xCC); //跳过序列号检查 Byte_W(0xBE); //读取温度 Temp_L=Byte_R(); //读取温度低 8 位 Temp_H=Byte_R(); //读取温度高 8 位 Data |=Temp_H; Data <<=8; Data |=Temp_L; return Data; } /******************************************************************** * DS18B20初始化函数 ********************************************************************/ bit DS18B20_Init(void) Maplead MCU Development Board http://shop63914145.taobao.com 197 { DIO=0; Delay(80); //延时 480us DIO=1; Delay(10); //延时 60us if(!DIO) //检查器件是否存在 { Delay(80); //给适当宽度的延时 return 1; //返回成功标志,退出 } return 0; } /******************************************************************** * 字写入函数 ********************************************************************/ void Byte_W(unsigned char Data) { unsigned char i; bit k; for(i=0;i<8;i++) { k=(bit)(Data & 0x01); DIO=0; //拉低数据线 15us Delay_15us(); DIO=k; //将数据加载至数据线 Delay(7); //45us 宽度的时间隙 DIO=1; Data >>=1; } } /******************************************************************** * 字读出函数 ********************************************************************/ unsigned char Byte_R(void) { unsigned char Data,i; for(i=0;i<8;i++) { DIO=0; //拉低 1us Data >>=1; DIO=1; //释放 Delay_4us(); //等待 DS18B20 上传数据后读取 if(DIO) Data |=0x80; Delay(8); } return Data; } Maplead MCU Development Board http://shop63914145.taobao.com 198 /******************************************************************** * 延时函数 ********************************************************************/ void Delay(unsigned int data Time) //延时时间为: (5+6*Time) us { while(Time--); } /******************************************************************** * 显示函数 ********************************************************************/ void Display(int Num) { unsigned char BIT[]={0,0,0,0,0,0,0,0}; //将器件中读出的温度值计算并分解成各个位,存入数组 BIT[] 中 unsigned char i; unsigned long Val; bit Flag_Neg=0; //负数标志 if(Num<0) //如果数值为负数 { Num=-Num; //转换成正数处理 Flag_Neg=1; //负数标志置位 } Val=(unsigned long)Num; Val=(Val*625); //计算出放大了 10000 倍的温度值(本为:Num = Num * 0.0625) if(Flag_Neg) //如果数值为负值 { if(Val<100000) //如果数值大于-10 则在数字的十位显示负号 BIT[7]=5; else //如果数值小于-10 则在数字的百位显示负号 BIT[7]=6; } BIT[0]=(unsigned char) (Val%10); //取出万分位 BIT[1]=( unsigned char) ((Val%100)/10); //千分位 BIT[2]=( unsigned char) ((Val%1000)/100); //百分位 BIT[3]=( unsigned char) ((Val%10000)/1000); //十分位 BIT[4]=( unsigned char) ((Val%100000)/10000); //个位 BIT[5]=( unsigned char) ((Val%1000000)/100000); //十位 BIT[6]=( unsigned char) ((Val%10000000)/1000000); //百位 P0=0x00; //清除显示 P2=LED_Bit[0]; P0=LED_Seg[BIT[0]]; //显示万分位 for(i=0;i<255;i++); //延时一小会,增加数码管的亮度 P0=0x00; P2=LED_Bit[1]; P0=LED_Seg[ BIT[1] ]; //显示千分位 Maplead MCU Development Board http://shop63914145.taobao.com 199 for(i=0;i<255;i++); P0=0x00; P2=LED_Bit[2]; P0=LED_Seg[BIT[2]]; //显示百分位 for(i=0;i<255;i++); P0=0x00; P2=LED_Bit[3]; P0=(LED_Seg[BIT[3]]); //显示十分位 for(i=0;i<255;i++); P0=0x00; P2=LED_Bit[4]; P0=(LED_Seg[BIT[4]]) | (LED_Dot); //显示个位& 小数点 for(i=0;i<255;i++); P0=0x00; if( BIT[5]|BIT[6] ) //十位与百位不同时为零,则显示十位 { P2=LED_Bit[5]; P0=LED_Seg[BIT[5]]; //显示十位 for(i=0;i<255;i++); } P0=0x00; if( BIT[6] ) //如果百位为零,则不显示百位 { P2=LED_Bit[6]; P0=LED_Seg[BIT[6]]; //显示百位 for(i=0;i<255;i++); } P0=0x00; if(Flag_Neg) { P2=LED_Bit[BIT[7]]; //如果为负值显示负号 P0=0x40; for(i=0;i<255;i++); } P0=0x00; } Maplead MCU Development Board http://shop63914145.taobao.com 200 27. 脉宽调制(PWM)输出 PWM 原理 脉冲宽度调制(PWM)是利用数字信号对模拟信号电平进行编码,从而控 制模拟输出的功率、频率大小等。 图 27-1 PWM 输出功率 如图 27-1 所示,有两个不同占空比的脉冲波,在这两个脉冲波中(假如高 电平代表功率输出,低电平代表停止输出),脉冲 1 的平均输出功率则为总功率 的 40%;脉冲 2 的平均输出功率则为总功率的 60%。 只要脉冲的周期足够短,就不会产生明显的闪烁、间停等情况。例如,利用 PWM 调节灯光的亮度,脉冲的周期为几十赫兹,人的眼睛就不会感觉到闪烁。 脉宽调制计数被广泛应用与调光、调速、通信(例如红外遥控)等领域。 很多的单片机片上集成有 PWM 输出控制器,可以很方便的输出精准的脉宽 调制波。而 STC90C 没有集成 PWM 控制器,因此只能采用软件模拟的形式输 出 PWM 调制波。 PWM 调节 LED 亮度演示程序 例程 27-1 PWM 调节 LED 亮度 /****************************************************************************** * 文件: PWM 控制 LED 亮度.c * 说明: * (1)晶振 12MHz 调速通过。 * (2)LED1 由暗变亮,由亮变暗循环。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include 脉冲 1 脉冲 2 Maplead MCU Development Board http://shop63914145.taobao.com 201 sbit LED = P1^0; void main(void) { unsigned char PWM, i, j, k; while(1) { for(PWM=0;PWM<=255;PWM++) { for(k=0;k<5;k++) { for(i=0;i #define WDTStart() WDT_CONTR=0x35 //启动看门狗,溢出时间约为 2 秒 #define WDTClr() WDT_CONTR=0x35 //清看门狗定时器(喂狗) sfr WDT_CONTR=0xE1; sbit LED1=P1^0; sbit LED2=P1^7; bit Flag=0; //是否进入死循环标志位 void Delay(void); void main(void) { unsigned char i; IT0 = 1; //外部中断 0 采用下降沿触发方式 EX0 = 1; //开外部中断 0 Maplead MCU Development Board http://shop63914145.taobao.com 204 EA = 1; //开总中断 for(i=0;i<3;i++) //如果执行次段程序说明刚启动或被复位 { LED1=0; //点亮 Delay(); LED1=1; //熄灭 Delay(); } while(1) { if(Flag) //如果 Flag 标志被置位则进入死循环停止喂狗 while(1); LED2=0; //点亮 Delay(); LED2=1; //熄灭 Delay(); WDTClr(); //喂狗 } } /*************************************************** * 外部中断 0 处理函数 ****************************************************/ void Int0_ISR() interrupt 0 using 1 { EA = 0; //关闭中断 Flag= 1; //置位标志位 EA = 1; } /*************************************************** * 延时函数 ****************************************************/ void Delay(void) { unsigned int xdata i; for(i=0;i<10000;i++); } Maplead MCU Development Board http://shop63914145.taobao.com 205 29. 51 系列单片机的省电模式 51 系列单片机的省电模式 在设计一些电池供电的移动设备时,往往需要考虑系统的功耗问题,需要在 最大程度上降低系统的总功耗,这时往往会使用到单片机的低功耗模式。 51 系列单片机有两种低功耗模式,分别为空闲模式和掉电模式。以 STC89 和 STC90 系列单片机为例,正常模式下的典型功耗为 4~7mA,而空闲模式下的 典型功耗为 2mA,掉电模式下的典型功耗在 0.1uA 以下。 51 系列单片机的空闲模式 空闲模式下,仅 CPU 停止工作,其余的片上外设均处于工作状态,STC 系 列单片机看门狗工作与否取决于看门狗 IDLE_WDT 特殊功能位的设定(见本文 P154 页看门狗定时器)。任何一个中断都将单片机从空闲模式下唤醒,单片机进 入执行空闲模式指令的下一条指令处继续执行操作。RST 引脚复位也可唤醒单片 机的空闲模式,但程序将从 0x0000 处重新开始执行。 51 系列单片机的掉电模式 掉电模式下,单片机处于停机状态,内部时钟停振,CPU 及片上外设(包 括看门狗)都停止工作,仅外部中断继续工作。STC 系列单片机的低压检测如果 被允许继续工作,则低压检测电路继续工作。单片机进入该模式后所有内部寄存 器及 I/O 口都维持在掉电模式启动前一刻的状态。 P3.2、P3.3 的外部中断可唤醒单片机,唤醒后单片机继续执行原来的操作。 RST 引脚复位也可唤醒单片机,但程序会重新从 0x0000 处重新执行。 51 系列单片机的电源管理特殊功能寄存器 表 29-1 电源控制(PCON)特殊功能寄存器 地址 B7 B6 B5 B4 B3 B2 B1 B0 PCON 87H SMOD - - - GF1 GF0 PD IDLE SMOD:串口速度加倍位。 GF0,GF1:用户自定义标志位。 PD:掉电模式启动位,将其置“1”后,单片机进入掉电模式。 IDLE:空闲模式启动位,将其置“1”后,单片机进入空闲模式。 Maplead MCU Development Board http://shop63914145.taobao.com 206 51 系列单片机的电源管理演示程序 例程 29-1 单片机掉电模式 /****************************************************************************** * 文件:单片机掉电模式.c * 说明: * (1)晶振 11.0592Mhz 调试通过。 * (2)启动后,单片机正常运行,按下 K2 后,LED1 点亮。 * (3)按下 K3 后,单片机进入掉电模式,此时按 K2 单片机无反应。 * (4)在掉电模式下,向单片机发生一个串口数据不能唤醒单片机。 * (5)按下 K1 后,外部中断被触发,单片机退出掉电模式。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include sbit K2=P3^3; sbit K3=P3^4; void main(void) { TMOD=0x20; //T1 方式 2 TH1 =0xFD; //波特率不必关心 TL1 =0xFD; TR1 =1; //启动 T1 SCON=0x50; //串口通信方式 1 ES =1; //启动串口中断 IT0=1; //下降沿触发 EX0=1; //使能外部中断 0 EA =1; //使能总中断 while(1) { P1=0xFF; while(!K2) P1 =0x01; if(!K3) PCON=0x02; //进入掉电模式 } } Maplead MCU Development Board http://shop63914145.taobao.com 207 /**************************************************** * 外部中断 0 处理 只是唤醒空闲模式,不做任何动作 *****************************************************/ void EX0_ISR() interrupt 0 {} /**************************************************** * 串口中断处理 唤醒空闲模式,清零标志位 *****************************************************/ void UART_ISR() interrupt 4 { TI=RI=0; } 例程 29-2 单片机空闲模式 /****************************************************************************** * 文件:单片机空闲模式.c * 说明: * (1)晶振 11.0592Mhz 调试通过。 * (2)启动后,单片机正常运行,按下 K2 后,LED1 点亮。 * (3)按下 K3 后,单片机进入空闲模式,此时按 K2 单片机无反应。 * (4)按下 K1 后,外部中断被触发,单片机退出空闲模式。 * (5)在空闲模式下,向单片机发生一个串口数据也可唤醒单片机。 * 作者:Shenney John ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include sbit K2=P3^3; sbit K3=P3^4; void main(void) { TMOD=0x20; //T1 方式 2 TH1 =0xFD; //波特率不必关心 TL1 =0xFD; TR1 =1; //启动 T1 SCON=0x50; //串口通信方式 1 Maplead MCU Development Board http://shop63914145.taobao.com 208 ES =1; //启动串口中断 IT0=1; //下降沿触发 EX0=1; //使能外部中断 0 EA =1; //使能总中断 while(1) { P1=0xFF; while(!K2) P1 =0x01; if(!K3) PCON=0x01; //进入空闲模式 } } /**************************************************** * 外部中断 0 处理 只是唤醒空闲模式,不做任何动作 *****************************************************/ void EX0_ISR() interrupt 0 {} /**************************************************** * 串口中断处理 唤醒空闲模式,清零标志位 *****************************************************/ void UART_ISR() interrupt 4 { TI=RI=0; } Maplead MCU Development Board http://shop63914145.taobao.com 209 30. *STC 系列单片机内部 E2PROM (该节内容多引用自 STC 单片机数据手册) STC 系列单片机的 E2PROM STC 系列单片机大部分型号内部集成有 E2PROM 存储器,该存储器断电后 内容不丢失。STC 系列单片机 E2PROM 是与程序空间分开的,利用 ISP/IAP 技 术可将内部 Data Flash 当 E2PROM 使用,擦写次数在 10 万次以上。 STC 系列单片机 E2PROM 可分为若干个扇区,每个扇区包含 512 字节。使 用时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同 的扇区,不一定要用满。数据存储器的擦除操作是按扇区进行的。 E2PROM 可用于保存一些需要在应用过程中需要进行修改并且掉电不丢失 的参数数据,如一些仪器仪表的某些设定值等。在用户程序中,可以对 E2PROM 进行字节读、字节编程或者扇区擦除操作。在工作电压 Vcc 偏低时,建议不要 进行 E2PROM/IAP 操作,因为低压下 E2PROM 不能进行写入或擦除操作。 ISP/IAP 有关的特殊功能寄存器 表 30-1 E2PROM/IAP 操作特殊功能寄存器 特殊功能寄存器 说明 地址 复位值 ISP_DATA E2PROM 操作数据寄存器 E2H 1111 1111B ISP_ADDRH E2PROM 操作数据地址高 8 位 E3H 0000 0000B ISP_ADDRL E2PROM 操作数据地址低 8 位 E4H 0000 0000B ISP_CMD E2PROM 操作命令寄存器 E5H xxxx xx00B ISP_TRIG E2PROM 操作触发寄存器 E6H xxxx xxxxB ISP_CONTR E2PROM 操作控制寄存器 E7H 000x x000B ISP_DATA:欲写入或读出 E2PROM 的 8 位数据存储在这个寄存器中。 ISP_ADDRH:欲写入或读出 E2PROM 的 8 位数据在 E2PROM 中的地址高 8 位存于此寄存器中。 ISP_ADDRL:欲写入或读出 E2PROM 的 8 位数据在 E2PROM 中的地址低 8 位存于此寄存器中。 ISP_CMD:E2PROM 操作命令寄存器,该寄存器的低 2 位分别为 M0,M1, 对 M0,M1 的设定决定了:停止 ISP 操作、写入、读出以及扇 区擦除等操作。 Maplead MCU Development Board http://shop63914145.taobao.com 210 表 30-2 ISP_CMD 寄存器位定义 B7 B6 B5 B4 B3 B2 B1 B0 - - - - - MS2 MS1 MS0 表 30-3 ISP_CMD 寄存器设定 MS2 MS1 MS0 模式 0 0 0 待机模式,无 ISP 操作。 0 0 1 对 E2PROM 进行字节读。 0 1 0 对 E2PROM 进行字节写入。 0 1 1 对 E2PROM 进行扇区擦除。 ISP_TRIG:ISP/IAP 操作时的命令触发寄存器。 在 ISPEN(ISP_CONTR.7)=1 时,对 ISP_TRIG 先写入 46h,再写入 B9h,ISP/IAP 命令才会生效。 ISP/IAP 操作完成后,ISP 地址高八位寄存器 ISP_ADDRH、ISP 地址低八位 寄存器 ISP_ADDRL 和 ISP 命令寄存器 ISP_CMD 的内容不变。如果接下来要对 下一个地址的数据进行 ISP/IAP 操作,需手动将该地址的高 8 位和低 8 位分别写 入 ISP_ADDRH 和 ISP_ADDRL 寄存器。 每次 ISP 操作时,都要对 ISP_TRIG 先写入 46H,再写入 B9H,ISP/IAP 命 令才会生效。 ISP_CONTR:ISP/IAP 命令寄存器。 表 30-4 ISP_CONTR 寄存器位定义 B7 B6 B5 B4 B3 B2 B1 B0 ISPEN SWBS SWRST - - WT2 WT1 WT0 ISPEN:ISP/IAP 功能允许位。为“1”时,允许 ISP/IAP 操作;为“0”时禁止 ISP/IAP 操作。 SWBS:软件选择从用户应用程序区启动(送 0),还是从系统 ISP 监控程序 区启动(送 1)。要与 SWRST 直接配合才可以实现。 SWRST:0:不操作;1:产生软件系统复位,硬件自动复位。 WT2、WT1、WT0:ISP/IAP 操作期间,系统等待时间设定位。 Maplead MCU Development Board http://shop63914145.taobao.com 211 表 30-5 WT0,WT1,WT2 位定义 设置等待时间 CPU 等待时间(机器周期,等于 12 个时钟周期) WT2 WT1 WT0 读 写 扇区擦除 与参数对应的系统时 钟 0 0 0 6 30 5471 5MHz 及以下 0 0 1 11 60 10942 10 MHz 及以下 0 1 0 22 120 21885 20 MHz 及以下 0 1 1 43 240 43769 40 MHz 及以下 例如,我们的系统时钟频率为 12MHz,该时钟大于 10MHz 而小于 20MHz, 为了保证 ISP/IAP 操作有足够的时间,我们应该选择 WT2、WT1、WT0 为:010B。 E2PRM 的地址 要对 E2PROM 进行操作必须指定字节读取或保存的地址,不同型号的 STC 单片机内 E2PROM 具有不同的地址空间,具体地址请查阅 STC 单片机官方提供 的数据手册。 欲对某一地址字节进行写入操作时,该地址字节原来的值必须为 0xFF(表 示已擦除),如果不为 0xFF 而强行写入,则写入操作会失败。 因此,在写入数据时需判断欲写入地址是否处于已擦除的状态,如果欲操作 的地址未擦除则需要对该地址所处的整个扇区进行擦除(不能进行单字节擦除) 方能写入新的数据。 进行扇区擦除时,给出该扇区内任意一个字节的地址都可定位该扇区,无需 指定扇区首地址。 STC90C54RD+的 E2PROM 读、写以及扇区擦除演示程序 例程 30-1 STC90C54RD+的 E2PROM 读、写以及扇区擦除演示程序 /****************************************************************************** * 文件:STC90_EEPROM.c * 说明: * (1)晶振 12Mhz 调试通过 * (2)单片机型号为 STC90C54RD+,其它型号的 EEPROM 地址不同需要改写。 * (3)启动后,单片机读取第一扇区 0~15 地址处的数据并循环显示。 * (4)按下 K1 键后,0~15 数据存入指定扇区的第 0~15 地址处。 * (5)按下 K2 键后,指定扇区被擦除。 * (6)开机后,可先按 K2 键,擦除扇区,关机,开机后按 K1 键,写入数据,再 * 关机,开机后按 K3 键盘,不擦除也不写入,直接读取看原来存的数据是否 * 丢失 * 作者:Shenney John Maplead MCU Development Board http://shop63914145.taobao.com 212 ****************************************************************************** * Copyright (C) 2010 by Shenney John, All Rights Reserved. ******************************************************************************/ #include #include #define ISP_OFF(); {ISP_CMD=0x00;ISP_CONTR=0x00;}//关闭 ISP 功能,防止误动作 #define ISP_ON(); ISP_CONTR=0x82 ; //等待模式为 20MHz 以下 #define E2PROMAddr 0x8000 //扇区首地址 unsigned char E2PROM_R(unsigned int); void E2PROM_W(unsigned char, unsigned int); void E2PROM_SectorErs(unsigned int); void Disp(unsigned char); sfr ISP_DATA = 0xE2; //STC90 单片机 ISP 数据 SFR 定义 sfr ISP_ADDRH = 0xE3; //STC90 单片机 ISP 地址高 8 位 SFR 定义 sfr ISP_ADDRL = 0xE4; //STC90 单片机 ISP 地址低 8 位 SFR 定义 sfr ISP_CMD = 0xE5; //STC90 单片机 ISP 命令 SFR 定义 sfr ISP_TRIG = 0xE6; //STC90单片机 ISP 触发 SFR 定义 sfr ISP_CONTR = 0xE7; //STC90 单片机 ISP 控制 SFR 定义 sbit K1=P3^2; //按键 1 定义 sbit K2=P3^3; //按键 2 定义 sbit K3=P3^4; //按键 2 定义 unsigned char Cnt=0; //显示计数 unsigned char code LED_Seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,//0~F 段码 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; void main(void) { unsigned char i=0, Num[16]; P0=0x40; //显示"-",表示等待输入 P3=0xFF; //P3 口为输入状态 while(1) { if(!K1) //如果 K1 按下 { for(i=0;i<16;i++)//写入数据 { E2PROM_W(i, E2PROMAddr+i); break; //退出 while 循环 } } if(!K2) //如果 K2 按下 { E2PROM_SectorErs(E2PROMAddr);//扇区擦除 break; //退出 while 循环 } Maplead MCU Development Board http://shop63914145.taobao.com 213 if(!K3) //如果 K3 按下 { break; //什么也不做,直接退出 while 循环 } } for(i=0;i<=15;i++) //读 0~15 地址单元的数据 { Num[i]=E2PROM_R(E2PROMAddr+i); } while(1) { Disp( Num[Cnt] ); //显示数据 Cnt++; if(Cnt>=16) //如果取足 16 个数据 Cnt=0; //从 0 地址重新取数据 } } /*************************************************** * 字节读 ****************************************************/ unsigned char E2PROM_R(unsigned int Addr) { unsigned char Dat; ISP_ON(); ISP_CMD = 0x01; //字节读模式 ISP_ADDRL = (unsigned char)Addr; //字节低 8 位地址 Addr >>= 8; //高 8 位移至低 8 位 ISP_ADDRH = (unsigned char)Addr; //字节高 8 位地址 ISP_TRIG = 0x46; //触发 ISP 操作 ISP_TRIG = 0xB9; _nop_(); Dat = ISP_DATA; //读数据 ISP_OFF(); return Dat; } /*************************************************** * 字节写 ****************************************************/ void E2PROM_W(unsigned char Dat, unsigned int Addr) { ISP_ON(); ISP_CMD = 0x02; //字节写模式 ISP_ADDRL = (unsigned char)Addr; //字节低 8 位地址 Addr >>= 8; //高 8 位移至低 8 位 ISP_ADDRH = (unsigned char)Addr; //字节高 8 位地址 ISP_DATA = Dat; //送数据 ISP_TRIG = 0x46; //触发 ISP 操作 ISP_TRIG = 0xB9; Maplead MCU Development Board http://shop63914145.taobao.com 214 _nop_(); ISP_OFF(); } /*************************************************** * 扇区擦除 ****************************************************/ void E2PROM_SectorErs(unsigned int Addr) { ISP_ON(); ISP_CMD = 0x03; //字节写模式 ISP_ADDRL = (unsigned char)Addr; //扇区低 8 位地址 Addr >>= 8; //高 8 位移至低 8 位 ISP_ADDRH = (unsigned char)Addr; //扇区高 8 位地址 ISP_TRIG = 0x46; //触发 ISP 操作 ISP_TRIG = 0xB9; _nop_(); ISP_OFF(); } /*************************************************** * 显示数字 ****************************************************/ void Disp(unsigned char Dat) { unsigned int data i; P0 = LED_Seg[Dat]; for(i=0;i<20000;i++); //延时定格一会数字显示 } Maplead MCU Development Board http://shop63914145.taobao.com 215 附录 A:USB 转串口驱动安装教程 本开发板板载了 USB 转串口模块,以方便没有串口的笔记本电 脑对本开发板进行操作。USB 转串口的驱动安装步骤请参照以下步 骤进行: 1. 安装驱动文件 图 1 安装驱动文件 请先不要连接开发板与电脑,打开开发板配套光盘中的“USB 转串口驱动”文件夹。 如果您用的操作系统是 windows98、2000、2003、xp、vista, 请打开“WIN 2000 XP VISTA”文件夹。 如果您用的操作系统是 windows7 操作系统,请打开“WIN7”文 件夹。 如图 1 所示,双击 SETUP.EXE 文件,将会出现图 2 所示的安 装画面。 Maplead MCU Development Board http://shop63914145.taobao.com 216 图 2 驱动安装画面 单击“INSTALL”按钮,过一段时间后,会出现图 3 所示画面, 单击确定。(如果按照过程中被杀毒软件等阻止,请选择解除阻止选 项) 图 3 驱动文件安装后所弹出的对话框 Maplead MCU Development Board http://shop63914145.taobao.com 217 2. 自动安装驱动程序 驱动所需的文件安装完毕后,我们接下来进行驱动程序的安装。 用所配套的 USB 线将开发板与计算机 USB 口相连接,这时, 计算机右下角的系统托盘会弹出如图 4 所示的画面。一段时间后系统 会自动识别出硬件系统,如图 5 所示。 图 4 系统托盘弹出发现新硬件对话框 图 5 系统自动识别硬件系统 等待一段时间后,系统会弹出如图 6 所示的画面,这时候选择“自 动安装软件”选项,并单击“下一步”按钮。 如图 7 所示,系统会自动安装 USB 转串口驱动程序。 Maplead MCU Development Board http://shop63914145.taobao.com 218 图 6 找到新的硬件向导对话框 图 7 USB 转串口驱动安装过程 Maplead MCU Development Board http://shop63914145.taobao.com 219 图 8 完成新硬件安装对话框 USB 转串口驱动程序安装完成后,会弹出图 8 所示的画面,单 击“完成”按钮。 图 9 安装成功对话框 如果一切顺利,安装完成后在右下角的系统托盘区会弹出图 9 所 示的对话框,表示 USB 转串口驱动程序已经安装成功并且可以使用 了。 3. 查看系统为硬件分配的端口号 在“我的电脑”图标上用右键单击,弹出图10所示的菜单。单击“设 Maplead MCU Development Board http://shop63914145.taobao.com 220 备管理器”选项,弹出图 11 所示窗口。 图 10 右击“我的电脑” 在“设备管理器”窗口中找到如图 11 所示的“端口(COM 和 LPT)”选项。 单击该选项左侧的“+”以展开该选项,这时会出现图 12 所示的窗 口。在该窗口中,我们可以看到“USB-SERIAL(COM X)”项。 在笔者的电脑上所显示的是“USB-SERIAL CH340(COM4)”, 不同电脑所显示的 COM 后面的数字是不一样的,该数字即为我们开 发板目前所用到的串口端口号,该号由电脑自动分配,下次连接开发 板时该号可能会有变化,因此每次使用之前我们都要在“设备管理器” 中查询该号,已备后面下载程序的时候使用。 Maplead MCU Development Board http://shop63914145.taobao.com 221 图 11 设备管理器窗口 图 12 USB 转串口端口号 Maplead MCU Development Board http://shop63914145.taobao.com 222 附录 B:STC 单片机程序下载方法 1. 连接电脑与开发板 用短路帽将 J20 的 RxD 与 TxD 进行连接,如图 1 所示。 图 1 用短路帽连接 RxD 与 TxD 用附带的 USB 数据线连接开发板与电脑,用附录 A 中第 3 节介 绍的方法查看系统为开发板分配的串口号(附录 A 图 11、图 12)。 附录 A 中例子的端口号为 COM4。 2. STC 单片机程序下载软件参数配置 打开配套文件夹 3 中的“STC 单片机程序下载软件”,如图 2 所示, 双击打开 STC_ISP_V483.exe。 软件打开后的界面如图 3 所示,软件的参数设置如下: ① MCU Type 选项中选择 STC90C5xRC/RD+ series 选项下 的 STC90C58RD+(本开发板配套的芯片型号,其它型 号芯片请自行选择)。 ② 单击“打开程序文件”按钮,选择要下载到单片机中的机器 ① Maplead MCU Development Board http://shop63914145.taobao.com 223 代码文件(HEX 或 BIN 为后缀的文件,例如,图 4 中选 择配套例程的“闪烁灯”程序)。 ③ COM 口选择,我们选择附录 A 中方法看到的“COM4”(各 人电脑中分配的端口号不同,请自行按照附录 A 方法查 看并根据实际进行选择)。 图 2 STC 单片机程序下载软件 ① ② ③ ④ Maplead MCU Development Board http://shop63914145.taobao.com 224 图 3 STC 单片机程序下载软件界面 图 4 STC 单片机程序下载软件界面打开程序文件界面 ④ 按下电源按钮,打开开发板的 USB 供电电源。电源开关 为自锁按钮,当采用 USB 供电方式时,按钮按下为开, 按钮弹起为关。 打开开发板电源后,按下图 3 所示的④号标注位置的 “Download/下载”按钮。这时,开发板的 RxD 发光管将会 点亮(见图 1 标注①位置)。这时候,关闭开发板电源(按 钮弹起,电源按钮见图 5),马上再打开电源(按钮按下), 这时,RxD 发光管与 TxD 发光管将会不停闪烁,等待一 段时间后程序下载完毕,如图 6 所示。 Maplead MCU Development Board http://shop63914145.taobao.com 225 图 5 电源按钮 图 6 程序下载完成 Maplead MCU Development Board http://shop63914145.taobao.com 226 3. 程序下载注意事项: (1) 下载前请确认单片机型号是否选择正确。 (2) 下载前请检查开发板的晶振、图 1 所示的短路帽是否正确安装。 (3) 下载前请确认串口号是否查看并设置正确。 (4) 下载时不要操作开发板。 (5) 下载时不要拔下 USB 线。 (6) 偶尔下载不成功,USB 线重新拔插一次(连接时间过久或输出 电流过大)。 (7) 开发板的排针插接太多外部器件的时候,USB 供电电流过大, 可能会影响程序下载,这时候需要拔下外接器件或去掉过多连 线,重新拔插 USB 线。 (8) 程序下载或待下载过程中不慎将 USB 线拔下时,串口下载软件 会死掉而无法操作,需要打开程序管理器强行关闭该程序,重 新启动。
还剩230页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

liu0018

贡献于2016-04-29

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf