单片机复习


编程题目:

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.段码的定义:

在这里插入图片描述

代码位D7D6D5D4D3D2D1D0
显示段dpgfedcba

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;		//“0”时,为电平触发,为“1”时,为下降沿触发
}
void InitExT1(void){
	EA = 1;
	EX1 = 1;
	IT1 = 1;		//“0”时,为电平触发,为“1”时,为下降沿触发
}
void key_clear()interrupt 0 { //外中断0控制清楚(P3^2)
	d1=d2=d3=d4=0;
	flag=0;
}

void key_stop()interrupt 2 {	//外中断1控制暂停(P3^3)
		flag = ~flag;
}

void cnt()interrupt 1{				//定时器中断 10ms计数
	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{			//定时器中断 5ms数码管扫描速率
	TH1 = 0x0EC;
  TL1 = 0x78;
	i++;
	seg = 0x00;
	if(i==4)
		i=0;
}
void main(){
	TMOD=0x11;		
//0001_0001(<GATE><C/T><M1><M0>)//定义方式1,不启动多控制中断方式,计数模式(用内部时钟信号)
	IP=1;
//IP默认值为00H,此时优先级顺序为:外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断 
//<--><--><PT2><PS:串口><PT1:T1中断><PX1:ET1中断><PT0:T0中断><PX0:ET0中断>
	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

EAESET1EX1ET0Ex0
AFHACHABHAAHA9HA8H

c.串行口中断标志寄存器(SCON

SM0SM1SM2RENTB8RB8TIRI
控制模式控制模式控制多机通讯使能接收发送的第8位数据j接收的第8位数据发送中断标志位接收中断标志位

d.定时器/计数器控制寄存器(TMOD

GATEC/TM1M0GATEC/TM1M0
T1 控制段1:计数/0:计时模式控制(H)模式控制(L)T0控制段1:计数/0:计时模式控制(H)模式控制(L)

e. 串口波特率控制寄存器(PCON

SMOD
波特率控制

2.初始化程序设计:(波特率只和定时器/计数器1有关

void init_serialcomm(void)
{
    SCON  = 0x50;       
//SCON: mode 1, 8-bit【无多机通讯】 REN  <M0><M1><M2><REN><TB8><RB8><TI><RI>
    TMOD |= 0x20;       
 //TMOD: timer 1, mode 2,8-bit  <GATE><C/T><M1><M0><GATE><C/T><M1><M0>==[计数器1][计数器0]
    PCON |= 0x80;       
//SMOD=1;加倍波特率 		<SMOD><--><--><--><--><--><-->
    TH1 = 0xF4;       
//Baud:4800  fosc=11.0592MHz 	 <计数器方式2,为8位计数器,自动装载,由TH1--TL1>
    IE |= 0x90;       
//Enable Serial Interrupt 	 <EA> <X> <X> <ES> <ET1> <EX1> <ET0> <EX0>
    TR1 = 1;          
// timer 1 run 		 驱动计数器
}

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)  //串行输入1个字节的控制字
{  	uchar i;
		dclk = 0;
	for(i=0;i<8;i++)
	{	din=wx>>7;
		wx<<=1;
		dclk=0;
		dclk=1;		  //上跳沿输入
	}
}

uint XPT2046_read()	 //读出12位的转换数据
{	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;  //设置为工作方式1 0101 0000
    TMOD=0x20;  //设置计数器工作方式2
    PCON=0x80;  //波特率加倍
    TH1=0xF3;   //计数器初始值,波特率为4800
    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]

定时器溢出率 = 计 数 速 率 256 − X = f o s c / 12 256 − X {\frac{计数速率}{256-X}=\frac{f_{osc}/12}{256-X}} 256X=256Xfosc/12

波 特 率 = 2 S M O D 32 ∗ f o s c 12 ∗ ( 256 − X ) {波特率 = \frac{2^{SMOD}}{32}*\frac{f_{osc}}{12*(256-X)}} =322SMOD12(256X)fosc

若晶振11.0592MHz,选用T1方式2定时器作为波特率发生器,波特率为2400bps

因为只有方式1、3得波特率是可调的,所以方式选择这两个。

设T1方式2定时,选择SMOD=0;

波 特 率 = 2 S M O D 32 ∗ f o s c 12 ∗ ( 256 − X ) {波特率 = \frac{2^{SMOD}}{32}*\frac{f_{osc}}{12*(256-X)}} =322SMOD12(256X)fosc = 2400

得:X=244=F4H

解:先求溢出率:2400 = 溢出率/32; 得:溢出率=76800

求初值:76800 = 计数速率/(256-X)= f o s c / 12 256 − X {\frac{f_{osc}/12}{256-X}} 256Xfosc/12 得:计数速率 = 244 【晶振用11.0592MHz来做】

定时器/计数器

1.相关得寄存器

a.中断允许寄存器(IE

EAESET1EX1ET0Ex0
AFHACHABHAAHA9HA8H

b.中断请求标志寄存器(TCON

TF1TR1TF0TR0IE1IT1IE0IT0
T1溢出中断T0溢出中断外部中断1定时器1中断外部中断0定时器中断0

d.定时器/计数器控制寄存器(TMOD

GATEC/TM1M0GATEC/TM1M0
T1 控制段1:计数/0:计时模式控制(H)模式控制(L)T0控制段1:计数/0:计时模式控制(H)模式控制(L)
2.定时器相关

在C51中我们可以利用的定时器/计数器只有两个:T0、T1

存在四种工作方式(12MHz):

方式0:计数器/定时器 为13位的1

方式1:计数器/定时器 为16位的 2

方式2:计数器/定时器为8位的【由硬件自动装载】3

方式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

  1. 最大可定时213x1us=8191us ~= 8.191ms ↩︎

  2. 最大可定时时间 216x1us=65535us ~= 65.535ms ↩︎

  3. 自动装载TH–>TL中重载,每次在定时器中断触发的时候,最大计时:28x1us=255us ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值