单片机考试编程题

单片机考试编程题
单片机考试编程题

一、C语言编程实现单片机I/0口控制数码管的显示

1.用定时0的方式1实现数码管两位59S循环计时(计时器)

思路方案:利用单片机的定时器/计数器定时和计数的原理,通过proteus 仿真软件来实现模拟实现。模拟利用AT89C51单片机、LED数码管实现秒表的计时。

其中一个两位数码管用来显示数据,一位用来显示个位秒,另一位用来显示十位秒。当计数超过范围时所有数码管全部清零重新计数。

程序代码如下:

#include

#define uchar unsigned char

#define uint unsigned int

uchar num,count,ge,shi;

void delay(uint);

void display(uchar,uchar);

uchar SEG[]={0xc0,0xf9,0xa4,0xb0,0x99, //显示数码管0-9数字

0x92,0x83,0xf8,0x80,0x98};

void main()

{

TMOD=0x01; //设置定时器工作方式 T0的工作方式为1

TH0=(65536-45872)/256; //装初值11.0592M晶振定时50ms数为45872

TL0=(65536-45872)%256;

EA=1; //开总中断

ET0=1; //开定时器0中断

TR0=1; //启动定时器0

while(1) //程序在这里不停的对数码管动态扫描同时等待中断发生{

display(shi,ge);

}

}

/*以下是设计中断服务程序的时间和显示*/

void T0_time()interrupt 1

{

TH0=(65536-45872)/256; //重装初值

TL0=(65536-45872)%256;

if(++num= =20) //如果到了20次,说明1秒时间到

{

num=0; //然后把num清0重新再记20次

if(++count==60) //这个数用来送数码管显示,到60后归0

count=0;

shi=count/10; //把一个2位数分离后分别送数码管显示,十位和个位

ge=count%10;

}

}

/*以下为延迟函数*/

void delay(uint xms)

{

uint i,j;

for(i=xms;i>0;i--) //延迟时间为 xms乘以50ms

for(j=110;j>0;j--);

}

/*以下为显示数码管的子函数*/

void display(uchar shi,uchar ge)

{

P3=0xfe; //打开P3.0,及打开数码管1引脚

P2=SEG[ge];

delay(20);

P3=0xfd; //打开P3.1,及打开数码管2引脚

P2=SEG[shi];

delay(20);

}

2. 基于单片机V1或V2实验系统,编写一个程序,实现以下功能:1)首先在数码管上显示“P_ _ _”4个字符;2)等待按键,如按了任何一个键,则将这4个字符清除,改为显示“0000”4个字符(为数字的0)。

#include

unsigned char code

Dig[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x 86,0x8e}; //gongyang数码管 0-F 代码

unsigned char k; //设置全局变量k 为键盘的键值

/************************************键盘延时函数****************************/

void key_delay(void) //延时函数

{

int t;

for(t=0;t<500;t++);

}

/************************************键盘扫描函数

******************************/

void keyscan(void) //键盘扫描函数

{

unsigned char a;

P2 = 0xf0; //键盘初始化

if(P2!=0xf0) //有键按下?

{

key_delay(); //延时

if(P2!=0xf0) //确认真的有键按下?

{

P2 = 0xfe; //使行线P2.4为低电平,其余行为高电平 key_delay();

a = P2; //a作为缓存

switch (a) //开始执行行列扫描

{

case 0xee:k=15;break;

case 0xde:k=11;break;

case 0xbe:k=7;break;

case 0x7e:k=3;break;

default:P2 = 0xfd; //使行线P2.5为低电平,其余行为高电平

a = P2;

switch (a)

{

case 0xed:k=14;break;

case 0xdd:k=10;break;

case 0xbd:k=6;break;

case 0x7d:k=2;break;

default:P2 = 0xfb; //使行线P2.6为低电平,其余行为高电平

a = P2;

switch (a)

{

case 0xeb:k=13;break;

case 0xdb:k=9;break;

case 0xbb:k=5;break;

case 0x7b:k=1;break;

default:P2 = 0xf7; //使行线P2.7为低电平,其余行为高电平

a = P2;

switch (a)

{

case 0xe7:k=12;break;

case 0xd7:k=8;break;

case 0xb7:k=4;break;

case 0x77:k=0;break;

default:break;

}

}

}

break;

}

}

}

}

/****************************** ***主函数*************************************/ void main(void)

{

while(1)

{

keyscan(); //调用键盘扫描函数

switch(k) //查找按键对应的数码管显示代码

{

case 0:P0=Dig[0];break;

case 1:P0=Dig[1];break;

case 2:P0=Dig[2];break;

case 3:P0=Dig[3];break;

case 4:P0=Dig[4];break;

case 5:P0=Dig[5];break;

case 6:P0=Dig[6];break;

case 7:P0=Dig[7];break;

case 8:P0=Dig[8];break;

case 9:P0=Dig[9];break;

case 10:P0=Dig[10];break;

case 11:P0=Dig[11];break;

case 12:P0=Dig[12];break;

case 13:P0=Dig[13];break;

case 14:P0=Dig[14];break;

case 15:P0=Dig[15];break;

default:break; //退出

}

}

}/**********************************end***************************************/

3.利用AT89S52单片机来制作一个0~99计时器,并且通过两个共阴数码管显示计数结果,数码管显示采用静态显示方式。

#include //包含AT89X52.H头文件

/*定义0~9十个数字的字型码表*/

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,

0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char Count; //定义变量放置计数数值

void delay10ms(void) //定义10ms延时函数

{

unsigned char i,j;

for(i=20;i>0;i--)

for(j=248;j>0;j--);

}

void main(void)

{

Count=0; //计数变量初始为0

For(Count=0; Count<10; Count++)

{

P0=table[Count/10]; //显示十位数

P2=table[Count%10]; //显示个位数

delay10ms();

}

while(1) //等待

}

4.将单片机与数码管接成图4-2所示静态显示方式,编程实现数码管每隔0.5s

的0-9数字显示。

#include

#define uchar unsigned char

sbit a=P0^5;

sbit b=P0^6;

sbit c=P0^7;

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,

0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char dispcount;

void delay02s(void)

{ unsigned char i,j,k;

for(i=10;i>0;i--)

for(j=200;j>0;j--)

for(k=248;k>0;k--);

}

void main(void)

{ while(1)

{for(dispcount=0;dispcount<10;dispcount++)

{

a=0;

b=0;

c=0;

P1=table[dispcount];

delay02s();

}

}

}

5.单片机与数码管接成动态显示方式,编程实现数码管的0-7数字显示。

#include

#define uchar unsigned char

unsigned char code tabledu[]={0x3f,0x06,0x5b,0x4f,0x66,

0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char code tablewe[]={0x1f,0x3f,0x5f,0x7f,0x9f,

0xbf,0xdf,0xff};

unsigned char dispcount;

void delay02s(void)

{ unsigned char i,j,k;

for(i=10;i>0;i--)

for(j=200;j>0;j--)

for(k=248;k>0;k--);}

void main(void)

{ while(1)

{for(dispcount=0;dispcount<8;dispcount++)

{ P0=tablewe[dispcount];

P1=tabledu[dispcount];

delay02s(); }

}

}

6.本任务是实现0~999的加1S计数显示。

#include

#define uchar unsigned char

sbit a=P0^5;

sbit b=P0^6;

sbit c=P0^7;

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char dispcount,bai,shi,ge;

unsigned int temp,aa;

void display();

void delay02s(void)

{ unsigned char i,j,k;

for(i=1;i>0;i--)

for(j=100;j>0;j--)

for(k=200;k>0;k--);}

void delay05s(void)

{ unsigned char s,m,t;

for(s=2;s>0;s--)

{ for(m=200;m>0;m--)

{ for(t=250;t>0;t--)

{;}

}

}

}

void main(void)

{ temp=0;

while(1) { delay05s();

delay05s();

temp++;

display(); } }

void display()

{if(temp==999)

{temp=0;}

bai=temp/100;

shi=temp%100/10;

ge=temp%10;

a=0; b=1; c=0;

P1=table[bai];

delay02s();

a=1; b=0; c=0;

P1=table[shi];

delay02s();

a=0; b=0; c=0;

P1=table[ge];

delay02s(); }

7.采用数码管进行数字时钟显示时间,并通过按键调整时间。

#include

#define uint unsigned int

#define uchar unsigned char

sbit key3=P0^3;//时调整

sbit key2=P0^2;//分调整

sbit key1=P0^1;//秒调整

sbit key0=P0^0;//全部清零键

uchar code tab1[]=

{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7d,0x07,0x7f,0x6f,0x00,0x40,0x80};//共阳0~9/-段码/点uchar code tab2[]={0x1f,0x3f,0x5f,0x7f,0x9f,0xbf,0xdf,0xff};//0~7依次位码表

uchar sec, min, hour, count; //定义秒,分,时,中断计数

void delay(uint z) //延时子函数

{

uint x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

//--------------------------------------------------------------

void init() //初始化T0函数

{

TMOD=0x01; //T0-方式1-16位计时器

TH0=(65536-50000)/256; //50MS

TL0=(65536-50000)%256; //晶振:12M计算

EA=1; //开总中断

ET0=1;//允许T0中断

TR0=1;//启动T0中断

}

void timer0() interrupt 1 //定时器函数

{

TH0=(65536-50000)/256; //50MS

TL0=(65536-50000)%256; //晶振:12M计算

count++; //50毫秒中断一次count便加1

if(count>=20) //中断了20次?(20*50=1秒)

{count=0;sec++;} //计数清零/秒加1

if(sec==60) //满了60秒?

{sec=0;min++;} //秒清零/分加1

if(min==60) //满了60分钟?

{min=0;hour++;} //分清零/时加1

if(hour==24) //满了24小时?

{hour=0;} //时清零

}

void display() //数码管显示子函数

{

uchar s ;

for(s=0;s<=10;s++)//扫描//控制显示刷新和按键速度

{

P1=tab1[hour/10];

P0=tab2[7]; delay(2);//时十位

P1=tab1[hour%10];

P0=tab2[6]; delay(2);//时个位

P1=tab1[11];

P0=tab2[5]; delay(2);//横

P1=tab1[min/10];

P0=tab2[4]; delay(2);//分十位

P1=tab1[min%10];

P0=tab2[3]; delay(2);//分个位

P1=tab1[11];

P0=tab2[2]; delay(2);//横

P1=tab1[sec/10];

P0=tab2[1]; delay(2);//秒十位

P1=tab1[sec%10];

P0=tab2[0]; delay(2);//秒个位

}

}

void key() //按键调整子函数

{

if(key1==0) //秒调整

{ delay(10);

if(key1==0){sec++;if(sec==60) sec=0;}//调到了60?

}

if(key2==0) //分调整

{ delay(10);

if(key2==0){min++; if(min==60) min=0;} //调到了60?

}

if(key3==0) //时调整

{ delay(10);

if(key3==0){hour++;if(hour==24) hour=0;} //调到了24?

}

if(key0==0) //全部归清零按

{ delay(10);

if(key0==0){sec = min = hour = 0;} //秒/分/时清零

}

}

void main() //主函数

{

init(); //T0初始化

while(1) //死循环

{

key(); //调整函数

display(); //显示函数

}

}

8.在8个LED数码管上,按从左到右的顺序,循环滚动显示数字“5”,每次滚动延时500ms #include

unsigned char LED;

void Delay(unsigned int milisec) //延时1ms

{

unsigned int i,j;

for(i=milisec;i>0;i--) //双重for循环实现延时1ms

for(j=110;j>0;j--);

}

void Main(void)

{

P0=0x6d; //显示数字“5”

while(1)

{

for(LED=0; LED<=7; LED++)

{

P2=LED; //选择LED,实现滚动显示

Delay(500); //延时500ms

}

}

}

9.在8个LED上稳定地显示“01234567”

#include

unsigned char code table[10] = {0x3f,0x06,0x5b,0x4f,0x66,

0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char code LED[8] = {0,1,2,3,4,5,6,7};

void Delay(unsigned int milisec) //延时1ms

{

unsigned int i,j;

for(i=milisec;i>0;i--)

for(j=110;j>0;j--);

}

void Main(void)

{

unsigned char i = 0;

while(1)

{

P0 = table[i]; // 取一个数的段位码

P2 = LED[i]; //点亮一个数码管

Delay(2); //延时2ms

i++; //移位

if(i == 8) i = 0; //重新开始

}

}

unsigned char code table[10] = {0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f};

10.在8个LED上显示计算机教研室的电话号码“68752219”#include

unsigned char code table[10] = {0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char code Number[8] = {6,8,7,5,2,2,1,9};

void Delay(unsigned int milisec) //延时1ms

{

unsigned int i,j;

for(i=milisec;i>0;i--)

for(j=110;j>0;j--);

}

void Main(void)

{

unsigned char i = 0,j;

while(1)

{

j = Number[i]; //取一个待显示的数

P0 = table[j]; // 取一个数的段位码

P2 = i; //点亮一个数码管

Delay(2); //延时2ms

i++; //移位

if(i == 8) i = 0; //重新开始

}

}

二.串行数据的发送和接收

1.用89C52串行口外接164串入/并出移位寄存器扩展8位并行输出口,外接165并入/串出移位寄存器扩展8位并行输入口。8位并行输出口的每位都接一个发光二极管,要求从8位并行输入口读入开关的状态值,使闭合开关对应的发光二极管点亮。

解:数据的输入输出通过RXD接收和发送,移位时钟通过TXD送出,74HC164用于串/并转换,74HC165用于并/串转换。

C语言程序清单:

#include

sbit P1_0=P1^0;

sbit P1_1=P1^1;

unsigned char data1;

void main()

{

SCON=0x10; //串行口方式0,允许接收

ES=1;

EA=1; //允许串行口中断

P1_0=0; //关闭并行输出

P1_1=1; //并行置入数据

P1_1=0; //开始串行移位

SBUF=0; //送入串行数据

while(1); //等待中断

}

void s_srv() interrupt 4 //中断服务程序

{

if(TI) //发送中断

{ TI=0;

P1_0=1; //打开并行输出

}

else //接收中断

{ RI=0;

data1=SBUF; //读取接收的数据

P1_0=0; //关闭并行输出

SBUF=~data1; //送入串行数据

P1_1=1; //为接收下一次

P1_1=0; //数据做准备

}

}

2.将片内RAM 50H~5FH中的数据串行发送,用第9个数据位作奇偶校验位,设晶振为11.059 2MHz,波特率为2 400b/s,编制串行口方式3的发送程序。

解:用TB8作奇偶校验位,在数据写入发送缓冲器之前.先将数据的奇偶位P写入TB8,这时,第9位数据作奇偶校验用,发送采用中断方式。

#include

unsigned char i=0;

unsigned char array[16] _at_ 0x50; //发送缓冲区

void main()

{ SCON=0xc0; //串行口初始化

TMOD=0x20; //定时器初始化

TH1=0xf4; TL1=0xf4;

TR1=1;

ES=1; EA=1; //中断初始化

ACC=array[i]; //发送第一个数据送

TB8=P; //累加器,目的取P位

SBUF=ACC; //发送一个数据

while(1); //等待中断

}

void server() interrupt 4 //串行口中断服务程序

{

TI=0; //清发送中断标志

ACC=array[++i]; //取下一个数据

TB8=P;

SBUF=ACC;

if(i==16) //发送完毕,

ES=0; //禁止串口中断

}

3.编写一个接收程序,将接收的16字节数据送入片内RAM 50H~5FH单元中。设第9个数据位作奇偶校验位,晶振为11.059 2 MHz,波特率为2 400b/s。

#include

unsigned char i;

unsigned char array[16] _at_ 0x50; //接收缓冲区

void main()

{

SCON=0xd0; //串行口初始化,允许接收

TMOD=0x20;

TH1=0xf4;

TL1=0xf4;

TR1=1;

for(i=0;i<16;i++) //循环接收16个数据

{ while(!RI); //等待一次接收完成

RI=0;

ACC=SBUF;

if(RB8==P) //校验正确

array[i]=ACC;

else //校验不正确

{ F0=1;

break;

}

}

while(1);

}

4.用第9个数据位作奇偶校验位,编制串行口方式3的全双工通信程序,设双机将各自键盘的按键键值发送给对方,接收正确后放入缓冲区(可用于显示或其它处理),晶振为11.059 2 MHz,波特率为9 600b/s。

解:因为是全双工方式,通信双方的程序一样。发送和接收都采用中断方式。

#include

char k;

unsigned char buffer;

void main()

{

SCON=0xd0; //串行口初始化, 允许接收

TMOD=0x20; //定时器初始化

TH1=0xfd;

TL1=0xfd;

TR1=1;

ES=1; //开串行口中断

EA=1; //开总中断

while(1)

{

k=key(); //读取按键按下键值

if(k!=-1) //无键按下返回-1

{

ACC=k; //将键值送累加器,取P位

TB8=P; //送TB8

SBUF=ACC; //发送

}

display(); //显示程序

}

}

void serial_server() interrupt 4

{ if(TI) //发送引起,清TI

TI=0;

else //否则,接收引起

{ RI=0;

ACC=SBUF; //读取接收数据

if(RB8==P) //校验正确,buffer=ACC; //存入缓冲区

}

}

三.定时器编程问题

1.设单片机的振荡频率为12MHz,用定时器/计数器0的模式1编程,在P1.0引脚产生一

个周期为1000μs的方波,定时器T0采用中断的处理方式。

#include //包含特殊功能寄存器库

sbit P1_0=P1^0; //进行位定义

void main( )

{ TMOD=0x01; //T0做定时器,模式1

TL0=0x0c;

TH0=0xfe; //设置定时器的初值

ET0=1; //允许T0中断

EA=1; //允许CPU中断

TR0=1; //启动定时器

while(1); //等待中断

}

void time0_int(void) interrupt 1

{ //中断服务程序

TL0=0x0c;

TH0=0xfe; //定时器重赋初值

P1_0=~P1_0; //P1.0取反,输出方波

}

2.设单片机的振荡频率为12MHz,用定时器/计数器0编程实现从P1.0输出周期为500μs

的方波。

# include //包含特殊功能寄存器库

sbit P1_0=P1^0;

void main( )

{ TMOD=0x02; //选择工作模式

TL0=0x06;

TH0=0x06; //为定时器赋初值

ET0=1; //允许定时0中断

EA=1;

TR0=1; //启动定时器0

while(1); //等待中断

}

void time0_int(void) interrupt 1

{

P1_0=~P1_0;

}

3.利用定时器T1的模式2对外部信号进行计数,要求每计满100次,将P1.0端取反。#include

sbit p1_0=p1^0; //进行位定义

void main ( )

{

TMOD=0x60; //T1工作在模式2,计数

TL1=0x9c; //装入计数(重装)初值

TH1=0x9c;

ET1=1; //允许定时器1中断

EA=1; //开中断

TR1=1 ; //启动定时器1

while(1);

}

void time0_int(void) interrupt 3 //中断服务程序

{

P1_0=~P1_0; //取反,产生方波

}

3.某应用系统要求通过P1.0和P1.1口分别输出脉冲周期为200μs和400μs的方波,

fosc=6MHz。

# include

sbit P1_0=P1^0; //进行位定义

sbit P1_1=P1^1;

void main( )

{

TMOD=0x03; //设置T0定时,工作在模式3

TL0=0xce; //设置TL0计数初值,产生200μs方波

TH0=0x9c; //设置TH0计数初值,产生400μs方波

ET0=1; //设置定时器0中断允许位

ET1=1; //设置定时器/计数//器1中断允许位

EA=1; //设置总中断允许位

TR0=1; //启动定时器T0

TR1=1; //启动定时器T1

while(1); //等待溢出

}

void time0L_int(void) interrupt 1

{ //T0中断服务程序

TL0=0xce; //定时器重赋初值

P1_0=~P1_0; //产生方波

}

void time0H_int(void) interrupt 3

{ //T1中断服务程序

TH0=0x9c; //定时器重赋初值

P1_1=~P1_1; //产生方波

}

相关主题
相关文档
最新文档