第九章 编程实例Word文档格式.docx
《第九章 编程实例Word文档格式.docx》由会员分享,可在线阅读,更多相关《第九章 编程实例Word文档格式.docx(29页珍藏版)》请在冰点文库上搜索。
![第九章 编程实例Word文档格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/2/04578ff3-78a3-4b20-b0ef-ec19877b36e5/04578ff3-78a3-4b20-b0ef-ec19877b36e51.gif)
AT89X52.H>
#include<
absacc.h>
//XBYTE函数
INTRINS.H>
//_nop_函数
#defineucharunsignedchar
#defineuintunsignedint
#defineDAADRXBYTE[0x8000]//ad0809的0通道地址
uchardd[8],m=0;
//转换结果在dd[8]中
uchar*ad_adr;
//全局变量
voidmain(void)
{uchari=0;
ad_adr=&
DAADR;
//给指针赋初值
DAADR=0x00;
//采样IN0通道,并启动采样
//避开EOC未变化的10μs
IE=0x81;
//开中断
while
(1)
{
//disp1(0);
在此可以显示,处理数据
}
}
voidad0809int(void)interrupt0using1//中断程序
{IE=0X00;
//关中断
dd[m]=*ad_adr;
//存贮转换结果
ad_adr++;
//指向下一个通道
ad_adr=0;
//开始下一次转换
m++;
//指向下一个数组元素
_nop_();
//根据晶振频率调整时间
if(m==8)
{m=0;
}
IE=0X81;
(0809采样)
例2I2C总线A/D转换(TLC0831)
TLC0831是8位逐次逼近电压型I2C总线A/D转换器,支持单信道输入串口输出,极性设置固定,不需寻址。
其内部有一采样数据比较器将输入的摸拟信号微分比较后转换为数字信号。
模拟电压的差分输入方式有利于抑制共模信号和减少或消除转换的偏移误差。
电压基准输入可调,使得小范围模拟电压信号转化时的分辨率更高。
由标准移位寄存器或微处理器将时间变化的数字信号分配到串口输出,当IN-接地时为单端工作,此时IN+为输入,也可将信号差分后输入到IN+与IN-之间,此时器件处于双端工作状态。
主要特点如下:
(1)8位分辨率;
(2)单信道差分输入;
(3)5V的电源提供0-5V可调基准电压;
(4)输入输出可与TTL和MOS兼容;
(5)总失调误差为1SB。
(6)串行时钟在250KHz时,转换时间为32μs。
典型的应用电路如下图:
TLC0831共8个引脚,CS:
为片选,低电平有效,并启动转换,在转换过程中必须保持低电平;
DO:
为数据输出端;
CLK:
时钟信号。
IN+:
模拟信号输入正极;
IN-:
模拟信号输入负极。
在转换过程中,转换数据同时从DO口输出。
TLC0831时序图如下:
按照时序图和电路图,可以编写出如下的应用程序,调用该程序一次可以完成一次转换,并将转换结果读入单片机A中:
编写的C51应用程序:
#include<
at89x52.h>
stdio.h>
typedefunsignedintuuint;
typedefunsignedcharuchar;
sbitadcdo=P1_0;
//定义TLC0831的数据线D0
sbitadccs=P1_2;
//定义TLC0831的时能线CS
sbitadcclk=P1_1;
//定义TLC0831的时钟线CLK
voiddelay(ucharx);
//定义廷时函数
ucharreadadc(void);
//定义读数据函数
voidadcck(void);
//定义时钟函数
voiddelay1(ucharx)
{
uchari;
for(i=0;
x;
i++)
{};
voidadcck(void)//时钟函数
adcclk=1;
delay1
(2);
adcclk=0;
ucharreadadc(void)//读出TLC0831转换数据函数
{
ucharch;
adccs=0;
adcck();
ch=0;
for(;
adcdo==1;
)adcck();
for(i=0;
8;
{adcck();
ch=(ch<
<
1)|adcdo;
}
adccs=1;
return(ch);
//返回值,即转换后的数据
voidmain(void)//主函数
uchara;
a=readadc();
ACC=a;
二、AT24C系列串行E2PROM
特点:
AT24CXX系列串行E2PROM是具有I2C总线接口功能的电可擦除串行EEPROM器件,具有掉电保护功能,功耗小,宽电源电压(2.5V-6.0V)的特点。
在智能仪器中,对于断电后需要保存的数据和可以在线修改的参数,采用该存储器是很方便的。
常用器件:
常用的有AT24C02(256字节),AT24C04(512字节),AT24C08(1024字节),AT24c16(2048字节)等。
地址确定:
AT24c系列串行E2PROM器件寻址字节中的最高4位(D7~D4)为1010;
器件地址中的低3位为引脚地址A2,A1,A0,对应器件寻址字节中的D3,D2,D1位,应用方法如下:
1)容量小于256字节的芯片(AT24C01/02),由引脚地址A2,A1,A0,组合可以扩展8片;
2)对于AT24C04(512字节),A0引脚不可用,由输入器件地址时编程为0或1;
由A1、A2确定还可以扩展4片;
3)对于AT24C08(1024字节),A0、A1引脚不可用,由输入器件地址时编程为0或1;
由A2确定还可以扩展2片;
4)对于AT24C16(2048字节),A0、A1、A2引脚均不可用,由输入器件地址时编程为0或1;
5)对于AT24C32以上的芯片,存储单元地址需要输入高位和低位两个字节,最大寻址能力为64K。
页面寻址:
以256字节为1页,则多于8位的寻址视为页面寻址。
在AT24C×
×
系列中,对页面寻址位采取占用器件引脚地址(A2,Al,A0)的办法,凡在系统中引脚地址用做页地址后,该引脚在电路中不得使用,悬空处理。
注意:
数据写入时有“帧格式”和“页格式”。
“帧格式”是一次写入一个8位数数据;
“页格式”是一次可以连续写入规定的数据个数,一般是8个数据。
注意区别“页格式”写入、读出与前面的页寻址的区别。
详细的写入格式见见下图。
写数据的时候,次序为:
开始信号→发器件地址→发应答信号→发数据地址→发应答信号→(数据传送)→停止。
读的时候,次序为:
开始信号→发送器件地址→发送应答信号→发送数据地址→发送应答信号→又发开始信号→发器件地址→发应答信号→(数据传送,同写入方式)→停止。
对器件的读写操作比较复杂,在应用时要注意研究。
例3AT89C52和AT24C02硬件连接和编程。
芯片中:
TEST为写保护,接地时允许正常读写,接高电平保护数据。
其余在前面均介绍过。
因A2、A1、A0=000,故单片机读AT24C02时,器件地址SLAR=1,0100001B=0A1H;
写AT24C02时,器件地址SLAW=10100000B=0A0H。
由于AT89C51没有I2C接口,必须进行编程模拟。
1)用C语言编写的读、写程序
编程技巧:
(1)必须弄懂I2C工作的基本原理
(2)严格按时序图和规定
参考程序如下:
AT89X52.h>
intrins.h>
//函数声明,次序安排好不用声明
//voidi2c_send8bit(unsignedchar);
//unsignedchari2c_receive8bit(void);
sbitSDA=P1^0;
//数据接口
sbitSCL=P1^1;
//时钟脉冲接口
//时钟脉冲为高电平时,数据从高变低,为开始信号
voidi2c_start(void)
SDA=1;
SCL=1;
SDA=0;
SCL=0;
return;
//时钟脉冲为高电平时,数据从低变高,为结束信号
voidi2c_stop(void)
//发送8位数据,数据保持稳定不变,SCL给一个脉冲
voidi2c_send8bit(unsignedcharb)
unsignedchara;
//数据移位控制变量
for(a=0;
a<
a++)
if((b<
a)&
0x80)//取最高位,先发送最高位
//最高位为1发送高电平
else
//最高位为0发送低电平
//产生时钟脉冲
//接收8位数据,时序同写,保持SCL为高电平,读SDA
unsignedchari2c_receive8bit(void)
//读的位数
unsignedcharb=0;
//保持SCL为高电平
b=b<
1;
//读1位左移1次
if(SDA==1)
b=b|0x01;
//按位或,从低位开始接收,移位8次到高位,先接收的是最高位
//结束时钟脉冲
//当SDA为低电平时,SCL给一个高电平脉冲为接收确认信号
biti2c_ack(void)
bitack;
//应答成功信号,为“0”应答成功
//将SDA拉高,保证低电平由I2C总线接口产生
//时钟由低变高
ack=1;
//应答不成功
ack=0;
//应答成功
//SDA为高电平,时钟由高变低,应答成功
return(ack);
//i2c_write(地址,数据),写一个字节
voidi2c_write(unsignedcharAddress,unsignedcharData)
do{
i2c_start();
//启动信号
i2c_send8bit(0xA0);
//送器件地址(写)
}while(i2c_ack());
//应答成功则器件地址写成功
i2c_send8bit(Address);
//送8位地址
i2c_ack();
//调应答
i2c_send8bit(Data);
//送8位数据
//调应答
i2c_stop();
//调停止
//i2c_read(地址,数据),读一个字节
unsignedchari2c_read(unsignedcharAddress)
unsignedcharc;
//存接收的数据
//开始
//注意:
送器件地址(写)
//=1,表示无确认,再次发送
//应答
i2c_send8bit(0xA1);
送器件地址(读)
c=i2c_receive8bit();
//读数据送变量C
return(c);
return(b);
//======主程序==========
unsignedchardd;
for(;
;
)//无限循环
i2c_write(0x00,0x55);
//给地址00写数据0x55
_nop_();
dd=i2c_read(0x00);
//从地址00开始读
}}
2)下面是采用单片机C语言和汇编语言混合编写的程序
//函数声明
externvoidsend8bit(unsignedchar);
externunsignedcharreceive8bit(char);
//注意说明格式
//发送开始信号
//发送结束信号
//发送接收确认信号
send8bit(0xA0);
send8bit(Address);
send8bit(Data);
send8bit(0xA1);
c=receive8bit(0x00);
//虽然无参数传递到汇编程序中,但必须给参数
)
下面是汇编语言程序,循环发送和接收8位数据。
NAMESENDANDREC
SDAEQUP1.0;
定义端口
SCLEQUP1.1
送八位数据
PUBLIC_SEND8BIT
SENDBYTESEGMENTCODE
RSEGSENDBYTE
_SEND8BIT:
MOVA,R7;
取数据
MOVB,#08H
SEND8BIT_A:
RLCA
MOVSDA,C
SETBSCL
NOP
CLRSCL
DJNZB,SEND8BIT_A
RET
接收八位数据
PUBLIC_RECEIVE8BIT
RECEIVE8BITSEGMENTCODE
RSEGRECEIVE8BIT
_RECEIVE8BIT:
MOVB,#08H
CLRA
SETBSDA
RECEIVE8IT_A:
SETBSCL
MOVC,SDA
RLCA
DJNZB,RECEIVE8IT_A
MOVR7,A;
送结果
RET
END
三、键盘和数码显示人机交互的C语言编程
1、行列式键盘与AT89C52的接口
键盘输入信息的主要过程是:
(1)单片机判断是否有键按下。
(2)确定按下的是哪一个键。
(3)把此步骤代表的信息翻译成计算机所能识别的代码,如ASCII或其它特征码。
例44×
4键盘的扫描程序。
扫描程序查询的内容为:
(1)查询是否有键按下。
首先单片机向行扫描P1.0~P1.3输出全为"
0"
扫描码F0H,然后从列检查口P1.4~P1.7输入列扫描信号,只要有一列信号不为"
1"
,即P1口不为F0H,则表示有键按下。
接着要查出按下键所在的行、列位置。
(2)查询按下键所在的行列位置。
单片机将得到的信号取反,P1.4~P1.7中的为1的位便是键所在的列。
接下来要确定键所在的行,需要进行逐行扫描。
单片机首先使P1.0为"
,P1.1~P1.7为"
,即向P1口发送扫描码FEH,接着输入列检查信号,若全为"
,表示不在第一行。
接着使P1.1接地,其余为"
,再读入列信号……这样逐行发"
扫描码,直到找到按下键所在的行,将该行扫描码取反保留。
当各行都扫描以后仍没有找到,则放弃扫描,认为是键的误动作。
(3)对得到的行号和列号译码,得到键值。
(4)键的抖动处理。
当用手按下一个键时,往往会出现所按键在闭合位置和断开位置之间跳几下才稳定到闭合状态的情况。
在释放一个键时,也会出现类似的情况,这就是键抖动,抖动的持续时间不一,通常不会大于10ms,若抖动问题不解决,就会引起对闭合键的多次读入,对于键抖动最方便的解决方法就是当发现有键按下后,不是立即进行逐行扫描,而是延时10ms后再进行。
由于键按下的时间持续上百毫秒,延时后再也不迟。
扫描函数的返回值为键特征码,若无键按下,返回值为0。
程序如下:
reg51.h>
#defineuintunsignedint
voiddlms(void)
voidkbscan(void);
voidmain(void)
ucharkey;
while
(1)
{key=kbscan();
dlms();
{uchari;
for(i=200;
i>
0;
i--){}
ucharkbscan(void)//键扫描函数
{ucharscode,recode;
P1=oxf0;
if((P1&
0xf0)!
=0xf0)//若有键按下
{dlms();
//延时去抖动
if((P1&
0xf0)!
=0xf0)
{scode=0xfe;
//逐行扫描初值
while((scode&
0x10)!
=0)
{P1=scode;
//输出扫描码
if((P1&
=0xf0)//本行有键按下
{recode=(P1&
0xf0)|0x0f;
return((~scode)+(~recode));
//返回特征字节码
else
scode=(scode<
<
1)|0x01;
//行扫描左移一位
return(0);
例5七段数码显示与AT89C51的接口
LED显示器工作在静态方式时,其阴极(或其阳极)点连接在一起接地(或+5V),每一个的端选线(a,b,c,d,e,f,g,dp)分别与一个8位口相连。
LED显示器工作在动态显示方式时,段选码端口I/O1用来输出显示字符的段选码,I/O2输出位选码。
I/O1不断送待显示字符的段选码,I/O2不断送出不同的位扫描码,并使每位显示字符停留显示一段时间,一般为1-5ms,利用眼睛的视觉惯性,从显示器上便可以见到相当稳定的数字显示。
确定的8155片内4个端口地址如下:
命令/状态口:
FFF0H
口A:
FFF1H
口B:
FFF2H
口C:
FFF3H
6位待显示字符从左到右依次放在dis_buf数组中,显示次序从右向左顺序进行。
程序中的table为段选码表,表中段选码表存放的次序为0-F等。
以下为循环动态显示6位字符的程序,8155命令字为07H。
absacc.h>
reg51.h>
#defineucharunsignedchar
#defineCOM8155XBYTE[0xfff0]
#