编程题目:
1.AD/DA
a.锯齿波
ORG 2000H
START:
MOV R0,#0FEH;P0端口地址
MOV A,#00H
LOOP:
MOVX @R0,A
INC A ;数据递增
SJMP LOOP
b.三角波
ORG 2000H
START:
MOV R0,#0FEH
MOV A,#00H
MOVX @R0,A
UP:
MOVX @R0,A ;数据递增
INC A
JNZ UP
DOWN:
DEC A ;;数据递减
MOVX @R0,A
JNZ DOWN
SJMP UP
c.矩形波
ORG 2000H
START:
MOV R0,#0FEH ;;FE为**P0**口的地址
LOOP:
MOV A,#data1 ;;第一个电平
MOVX @R0,A
LCALL DELAY1
MOV A,#data2 ;;第二个电平
MOVX @R0,A
LCALL DELAY2
SJMP LOOP
技术指标:
(1)分辨率;(2)建立时间;(3)精度
(1)分辨率指输入给AD转换器的单位数字量变化引起的模拟量输出变化。
(2)描述AD转换器转换快慢的一个参数
(3)位数越多精度越高
D/A的两种工作方式:(硬件链接方式)
a.单缓冲方式:指DAC0832内部的两个数据缓冲器有一个处于直通方式,另外一个处于受C51控制的锁存方式。在实际应用当中,如果只有一路模拟量输出,或者不要求多路同步输出时,可采用单缓冲方式。

b.双缓冲方式:对于DA转换,要求同步输出时,必须采用双缓冲同步方式,这种方式下,数据量的输入和AD转换是分两步进行的。单片机必须通过LE1来锁存待转换数字量,通过LE2来启动D/A转换

ADC0809硬件联接
技术指标:
(1)转换时间和转换效率(转换时间的倒数) ;(2)分辨率:1/2nx100%; n为量化时的位数
数码管
1.段码的定义:

| 代码位 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
| 显示段 |
dp |
g |
f |
e |
d |
c |
b |
a |
a.静态显示
b.动态显示
原理:在某一时刻,只让某一位选线处于选通状态,而其他各个位选线处于关闭状态,同时段码线上输出相应要显示的字符的段选信号,这样就可以使得多个数码管中的一个发光显示,而其他的数码管处于熄灭状态,在下一个时刻同样的来显示另外的数码管。虽然字符在不同的时间显示,但由于LED显示器的余晖和人眼的视觉暂留效应作用,只要每一位显示的时间间隔足够短,就会出现多个数码管同时显示的假象!!!
#include <reg52.h>
typedef unsigned int u16;
typedef unsigned char u8;
#define seg P0
#define sel P2
u8 smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
u8 d1=0,d2=0,d3=0,d4=0;
bit flag=0;
u8 i=0;
void delay5ms(){
unsigned char a,b;
for(b=19;b>0;b--)
for(a=130;a>0;a--);
}
void InitTimer0(void){
TH0 = 0x0D8;
TL0 = 0x0F0;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void InitTimer1(void){
TH1 = 0x0EC;
TL1 = 0x78;
EA = 1;
ET1 = 1;
TR1 = 1;
}
void InitExT0(void){
EA = 1;
EX0 = 1;
IT0 = 1;
}
void InitExT1(void){
EA = 1;
EX1 = 1;
IT1 = 1;
}
void key_clear()interrupt 0 {
d1=d2=d3=d4=0;
flag=0;
}
void key_stop()interrupt 2 {
flag = ~flag;
}
void cnt()interrupt 1{
TH0 = 0x0D8;
TL0 = 0x0F0;
if(flag==0){
if(d1==9){
d1 = 0;
if(d2 == 9){
d2 = 0;
if(d3==9){
d3=0;
if(d4==5)
d4=0;
else
d4++;
}
else
d3++;
}
else
d2++;
}
else
d1++;
}
else
;
}
void delay()interrupt 3{
TH1 = 0x0EC;
TL1 = 0x78;
i++;
seg = 0x00;
if(i==4)
i=0;
}
void main(){
TMOD=0x11;
IP=1;
InitExT0();
InitExT1();
InitTimer0();
InitTimer1();
while(1){
sel =i;
switch(i){
case 0: seg = smgduan[d4];break;
case 1: seg = smgduan[d3]+128;break;
case 2: seg = smgduan[d2];break;
case 3: seg = smgduan[d1];break;
default: seg = 0;
}
}
}
矩阵键盘
2.按键消抖原理
常用软件方法去抖,即检测出键闭合后执行一个延时程序,5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。当检测到按键释放后,也要给5ms~10ms的延时,待后沿抖动消失后才能转入该键的处理程序。>
一般来说,软件消抖的方法是不断检测按键值,直到按键值稳定。实现方法:假设未按键时输入1,按键后输入为0,抖动时不定。可以做以下检测:检测到按键输入为0之后,延时5ms~10ms,再次检测,如果按键还为0,那么就认为有按键输入。延时的5ms~10ms恰好避开了抖动期。
3.矩阵键盘:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
void matrixkeyscan()
{
uchar temp,key;
P3=0xfe;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xee:
key=0;
break;
case 0xde:
key=1;
break;
case 0xbe:
key=2;
break;
case 0x7e:
key=3;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
P3=0xfd;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xed:
key=4;
break;
case 0xdd:
key=5;
break;
case 0xbd:
key=6;
break;
case 0x7d:
key=7;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
P3=0xfb;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xeb:
key=8;
break;
case 0xdb:
key=9;
break;
case 0xbb:
key=10;
break;
case 0x7b:
key=11;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
P3=0xf7;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xe7:
key=12;
break;
case 0xd7:
key=13;
break;
case 0xb7:
key=14;
break;
case 0x77:
key=15;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
}
串口
1.相关寄存器:
a.中断允许寄存器(IE)
| EA |
– |
– |
ES |
ET1 |
EX1 |
ET0 |
Ex0 |
| AFH |
– |
– |
ACH |
ABH |
AAH |
A9H |
A8H |
c.串行口中断标志寄存器(SCON)
| SM0 |
SM1 |
SM2 |
REN |
TB8 |
RB8 |
TI |
RI |
| 控制模式 |
控制模式 |
控制多机通讯 |
使能接收 |
发送的第8位数据 |
j接收的第8位数据 |
发送中断标志位 |
接收中断标志位 |
d.定时器/计数器控制寄存器(TMOD)
| GATE |
C/T |
M1 |
M0 |
GATE |
C/T |
M1 |
M0 |
| T1 控制段 |
1:计数/0:计时 |
模式控制(H) |
模式控制(L) |
T0控制段 |
1:计数/0:计时 |
模式控制(H) |
模式控制(L) |
e. 串口波特率控制寄存器(PCON)
2.初始化程序设计:(波特率只和定时器/计数器1有关)
void init_serialcomm(void)
{
SCON = 0x50;
TMOD |= 0x20;
PCON |= 0x80;
TH1 = 0xF4;
IE |= 0x90;
TR1 = 1;
}
3.多机通讯过程:
a.原理:
在串行口以方式2或者方式3接收时,若SM2=1,表示设置为多及通信,这时:
1.接收到的第9为数据为1时,数据才装入SBUF并且置中断标志RI=1,向CPU发出中断请求
2.接收到的第9为数据为0时,则不会产生中断标志,信息被抛弃。
b.多机通讯的工作过程
主机的RXD与所有从机的TXD相连接。
(1)从机初始化程序串行口中断,将串行口编程为方式2或者方式3接收,即9为数据异步通信方式,且SM2和REN位置1,使得从机只处于多及通讯且接收地址帧的状态。
(2)在主机和某一个从机通信之前,先将对应的设备地址通过串口发送出去,地址信息第9位为“1”,【和传送数据的区别在于数据的第9位为“0”】。当主机向各从机发送地址时,各从机的串口接收到的第9为数据为RB8=1;且由于SM2=1,则中断标志位RI置“1”,从机响应串口中断,执行中断服务程序,在中断服务程序中,判断主机发送的地址是否是本机的地址,若是本机地址,则使该从机SM2=0(即关闭多机通讯方式),准备接收主机发送的数据;若不相符合,则仍然保持SM2=1;【因为数据的第9位为0,SM2=0时对这一位不敏感;但是当SM2=1时,只对这一位的高电平敏感,从而实现定向传数据【多机通讯】】。

4.实验程序(AD采样串口传输)
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define sel P1
#define seg P0
uchar i;
uchar code smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
sbit cs= P2^4;
sbit dclk = P2^7;
sbit din = P2^6;
sbit dout = P2^5;
void delay(uint i){
while(i--);
}
void XPT2046_writebyte(uchar wx)
{ uchar i;
dclk = 0;
for(i=0;i<8;i++)
{ din=wx>>7;
wx<<=1;
dclk=0;
dclk=1;
}
}
uint XPT2046_read()
{ uint rx=0;
uchar i;
for(i=0;i<12;i++)
{ rx<<=1;
dclk=1;
dclk=0;
rx|=dout;
}
return(rx);
}
uint getdata(uchar cmd)
{
uchar i;
uint value;
dclk = 0;
cs = 0;
XPT2046_writebyte(cmd);
for(i=6; i>0; i--);
dclk = 1;
dclk = 0;
value=XPT2046_read();
cs = 1;
return value;
}
void initcomm(void)
{
SCON=0x50;
TMOD=0x20;
PCON=0x80;
TH1=0xF3;
TL1=0xF3;
EA=1;
ES=1;
TR1=1;
}
void uart_rx(uchar ch)
{
SBUF=ch;
while(TI==0);
TI=0;
}
void main(){
uint send_data = 0;
uchar d1,d2,d3,d4;
uchar i,j;
initcomm();
while(1){
send_data=getdata(0xa4);
d4=send_data/1000;
send_data = send_data%1000;
d3=send_data/100;
send_data = send_data%100;
d2=send_data/10;
send_data = send_data%10;
d1=send_data/1;
for(j=0;j<10;j++){
for(i=0;i<4;i++){
delay(300);
sel =i;
switch(i){
case 0: seg = smgduan[d4];break;
case 1: seg = smgduan[d3];break;
case 2: seg = smgduan[d2];break;
case 3: seg = smgduan[d1];break;
default: seg = 0;
}
}
}
uart_rx(d4+48);
uart_rx(d3+48);
uart_rx(d2+48);
uart_rx(d1+48);
uart_rx(0x0A);
}
}
四种工作方式(方式1、3的波特率与T1计数器有关)
方式0:波特率固定 fosc/12[^串行方式0]
方式1:波特率 = 2SMOD/32*定时器T1溢出率[^串行方式1]
方式2:波特率 = 2SMOD/64*fosc [^串行方式2]
方式3:波特率 = 2SMOD/32*定时器T1的溢出率 [^串行方式3]
定时器溢出率 = 256X计数速率=256Xfosc/12
波特率=322SMOD12(256X)fosc
若晶振11.0592MHz,选用T1方式2定时器作为波特率发生器,波特率为2400bps
因为只有方式1、3得波特率是可调的,所以方式选择这两个。
设T1方式2定时,选择SMOD=0;
波特率=322SMOD12(256X)fosc = 2400
得:X=244=F4H
解:先求溢出率:2400 = 溢出率/32; 得:溢出率=76800
求初值:76800 = 计数速率/(256-X)=256Xfosc/12 得:计数速率 = 244 【晶振用11.0592MHz来做】
定时器/计数器
1.相关得寄存器
a.中断允许寄存器(IE)
| EA |
– |
– |
ES |
ET1 |
EX1 |
ET0 |
Ex0 |
| AFH |
– |
– |
ACH |
ABH |
AAH |
A9H |
A8H |
b.中断请求标志寄存器(TCON)
| TF1 |
TR1 |
TF0 |
TR0 |
IE1 |
IT1 |
IE0 |
IT0 |
| T1溢出中断 |
|
T0溢出中断 |
|
外部中断1 |
定时器1中断 |
外部中断0 |
定时器中断0 |
d.定时器/计数器控制寄存器(TMOD)
| GATE |
C/T |
M1 |
M0 |
GATE |
C/T |
M1 |
M0 |
| T1 控制段 |
1:计数/0:计时 |
模式控制(H) |
模式控制(L) |
T0控制段 |
1:计数/0:计时 |
模式控制(H) |
模式控制(L) |
2.定时器相关
在C51中我们可以利用的定时器/计数器只有两个:T0、T1
存在四种工作方式(12MHz):
方式0:计数器/定时器 为13位的
方式1:计数器/定时器 为16位的
方式2:计数器/定时器为8位的【由硬件自动装载】
方式3:计数器/定时器为两个8位的(只有T0能够工作在方式3,且此时T1停止计数)[^方式3]
装载值的计算:对于12MHz的晶振
例如:我们要计时100us,采用T0\T1的方式0、1、2都可以
方式0: (213 - X)*1us =100us; 可得:X = 8091 = 1F9B
方式1: (216 - X)*1us = 100us 可得:X = 65435 = FF9B
方式2: (28 - X)*1us = 100us; 可得:X = 155 = 9B
;;;;;;;;;;;;;;;;;;;;; 中断流水灯【T0方式1】 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ORG 0000H
AJMP START
ORG 000BH;
LJMP TIMER0;
ORG 0100H;
START:
MOV TMOD,#01H;
MOV TH0,#3CH;
MOV TL0,#B0H;
MOV A,#FEH;
MOV R0,#20H;
MOV IE,#10000010B;
MOV IP,#10B;
SETB TR0;
MOV P1,A;
SJMP $;
TIMER0:
DJNZ R0,LOOP;
MOV R0,#20;
MOV P1,A;
RL A;
LOOP:
MOV TH0,#3CH;
MOV TL0,#B0H;
RETI
END
********************************* 1s定时 *********************************
ORG 0000H
RESET:
LJMP MAIN
ORG 000BH
LJMP IT0P
ORG 1000H
MAIN:
MOV SP.#60
MOV B,#0AH
MOV TMOD,#01H
MOV TL0,#0B0H
MOV TH0,#3CH
SETB TR0
SETB ET0
SETB EA
HERE:
SJMP HERE
IT0P:
MOV TL0,#0B0H
MOV TH0,#3CH
DJNZ B,LOOP
CLR TR0
LOOP:
RETI
|