基本模型的建立
西安誉通光电测控有限责任公司
2010/4/21 17:10:04>> 进入商铺
写给我的兄弟姐妹们十
―基本模型的建立(图+程序)
上学的时候我“理科”学的很不错,其中很重要的原因之一就是我在学习的时候注重“基本模型”的建立,学习“嵌入式开发”也不例外,我们知道“单片机和外围功能器件构成基本硬件系统”+输入控制+输出控制=“目的系统”,很多书上从多个方面阐述其工作机理,要了解个中究竟就去看书吧;我在此只按照自己的理解方式给大家划分和讲解,目的是整理出思路来:不论键盘、鼠标等等输入,还是LCD、LED、CRT的显示,继电器、AD、DA等等,对于单片机来讲只是“控制方式”不同,而控制方式一般可分为---总线方式和I/O模拟方式;
那么首先要建立的模型是:
1. 单片机+键盘+LED灯;
这里的键盘是低电平有效,程序里用查询方式,当然你也可以高电平有效方式,把键盘和电阻的位置调换就可以了,同时可以用中断方式,当多个键盘共用一个中断的时候加一个74HC4078就可以了,如果牵扯到电平取反则加一个74HC04即可;这个实验是练习基本的I/O口控制;
2. 单片机+LCD;
使用总线控制和I/O控制两种方式来控制LCD;
3. 单片机+通信+LED数码等等(寄存器的设置+基本通信协议的理解+I/O模拟控制等等)具体有例子程序;
/* 实验一 LED流水灯 */
#Include <REG51.H>
void delay(void)
{ unsigned int i,j,k,l;
for(i=0;i<=27000;i++)
{j++; k++;l++;};
}
void main (void)
{ unsigned char i,c[4] = {0xef,0xdf,0xbf,0x7f};// 从左往右流水
i = 0;
while(1)
{ P3 = c[i & 3];
i++;
delay();
}
}
//=========================================================================
// 实验二 用一位数码管循环显示0~9
#Include <REG51.H>
#define U8 unsigned char
code U8 tab[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28};
void delay(void)
{ unsigned int i,j,k,l;
for(i=0;i<=27000;i++)
{j++; k++;l++;};
}
void main(void)
{ U8 i;
P2_4=0;
while(1)
{ P0 = tab[i];
delay();
i++;
if(i==10) i = 0;
}
}
//=============================================================================
// 实验三 LED数码管的动态驱动
#Include <REG51.H>
#define U8 unsigned char
U8 tab[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28};
U8 scn[]={0x7f,0xbf,0xdf,0xef};//先点亮左边一个数码管
U8 buf[4]={0,0,0,0};// 显示缓冲区,开机先显示"0000"
U8 cnt = 0; // 扫描计数
void main(void)
{ EA = 1; // 允许中断
TMOD = 0x01; // 设定时器0为模式1(16位)
ET0 = 1; // 定时器0中断允许
TH0 = 0xee; // 晶振11.0592MHz,5mS
TL0 = 0;
TR0 = 1; // 开始计数
while(1); // 死循环,等待中断
}
void timeint(void) interrupt 1 // 定时器0中断服务程序
{ char i;
TH0 = 0xee; // 设置定时器时间常数
TL0 = 0;
i = cnt & 0x03; // 求应点亮的LED号(从左到右依次为 0,1,2,3)
P0 = tab[buf[i]]; // 笔划代码送P0口
P2 = scn[i]; // 控制扫描码送P2口
if(cnt==200)
{ cnt=0; // 到1秒钟,显示的数字加一
for(i=3;i>=0;i--)
{ buf[i]++;
if(buf[i]==10) buf[i]=0;// 加到10向前进位
else break;
}
}
cnt++;
}
//====================================================================
// 实验四 自动演奏乐曲-康定情歌
#Include <REG51.h>
#define U8 unsigned char
code unsigned int cyc[]={1800,1600,1440,1351,1200,1079,960};//音阶1-7的半周期数
code U8 tone[]={13,15,16,16,15,16,13,12,12,13,15,16,16,15,16,13,13, 13,15,16,
16,15,16,13,12,12,15,13,12,13,12,11,12,6,6,12,15,13,12,6,6,15,13,12,13,12,11,
12,6,5,6,0xff};// 乐曲《康定情歌》的简谱表
code U8 time[]={8,8,8,4,4,8,8,12,4,8,8,8,4,4,8,16,8,8,8,8,4,4,8,8,12,4,8,8,4,4, 4,4,8,24,8,24,8,24,8,16,8,8,8,4,4,4,4,8,16,8,32};// 节拍表
U8 H0,L0,cnt;
void cntint0(void) interrupt 1 // 定时器0中断用于产生音阶方波
{ TH0=H0;
TL0=L0;
P2_3=~P2_3; // P2.3是音乐信号输出脚,P2.3反相,产生方波
}
void cntint1(void) interrupt 3 // 定时器1中断用于产生节拍延时
{ cnt++; // 计数初值为0,所以不用赋值
}
void main(void)
{ U8 i,a,t;
unsigned int b;
next:TMOD=0x11;
EA=1;
ET0=1;
ET1=1;
cnt=0;
TR1=1;
i=0;
while(1)
{ t=tone[i]; // 读音调
if(t==0xff) break; // 0xff是结束符
if(t!=0) // 0 是休止符
{ b=cyc[t%10-1]; // 根据基本音阶,求出半周期数
if(t<10) b=b*2; // 若是低八度音阶,半周期数加倍
if(t>20) b=b/2; // 若是高八度音阶,半周期数减半
H0=(65536-b)/256; // 根据半周期数,计算T0初值的高字节和低字节
L0=(65536-b)%256;
TR0=1; // 启动定时器0发音
}
cnt=0;
a=time[i]; // 读节拍
while(a>cnt);
TR0=0;
i++;
for(b=0;b<1000;b++); // 稍加延时,增强节奏感
}
P2_3=1; // 关闭喇叭
while(P3_2==1); // 等待按INT键
goto next; // 重放一遍
}
//===========================================================================
// 实验五 加法计算器
#Include <REG51.H>
#define U8 unsigned char
#define key_port P1
code U8 kcode[]={0xb7,0xbe,0xde,0xee,0xbd,0xdd,0xed,0xbb,0xdb,0xeb,0xd7,0xe7};
//反转码对应键值 0 1 2 3 4 5 6 7 8 9 A B
code U8 disp[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28,0xff};
U8 buf[4]={0,0,0,0};
U8 cnt=0;
U8 scn[]={0x7f,0xbf,0xdf,0xef};// 先点亮左边一个数码管
void delay_ms(U8 ms)
{ U8 i,j;
for(i=0;i<100;i++)
{ for(j=0;j<ms;j++);};
}
U8 key(void)
{ U8 a,r;
delay_ms(20); // 延时20毫秒,消除按键抖动
if(key_port == 0xf0) goto rn;
a = key_port;
key_port = a | 0x0f;
delay_ms(20);
a = key_port;
for (r = 0;r <= 11;r++)
{ if(a == kcode[r]) break;};
if(r > 11) r = 0xff; //0xff表示无效
rn: key_port = 0xf0;
return r;
}
void main(void)
{ U8 k,i,pf; // pf为按过加号键的标志
int p,p1,p2, // p1,p2为两个加数,p为和
TMOD = 0x01; // 设定时器0为模式1(16位)
TH0 = 0xee; // 晶振11.0592MHz,5mS
TL0 = 0;
TR0 = 1; // 开始计数
EA = 1; // 允许中断
ET0 = 1; // 定时器0中断允许
key_port = 0xf0;
pf = 0; // 清除加号标志
p = 0;
delay_ms(20);
while(1) // 循环
{ if (key_port != 0xf0)
{ k = key();
if (k < 10)
{ if((p1==0)&&(p2==0))for(i=0;i<=3;i++) buf[i] = 0;//清空显示缓冲区
else for(i=1;i<=3;i++) buf[i-1]=buf[i];// 数字左移一位
buf[3] = k;// 在个位显示刚按的数字
if(pf==0) p1 = p1 * 10 + k;
else p2 = p2 * 10 + k;
}
else
{ if(pf == 1)
{ p = p1 + p2;
p1 = 1000;
for(i=0;i<3;i++)
{ buf[i] = p / p1;
p = p - p1 * buf[i];
p1 = p1 / 10;
}
buf[3] = p;
p = 0;
p1 = 0;
p2 = 0;
pf = 0;
}
else
{ pf = 1;
p2 = 0;
for(k=0;k<=3;k++) buf[k] = 0;
}
}
while(key_port != 0xf0);// 等待按键抬起
delay_ms(20);
while(key_port != 0xf0);
}
}
}
void timeint(void) interrupt 1 // 定时器0中断服务程序
{ unsigned char i,s;
TH0 = 0xee; // 设置定时器时间常数
TL0 = 0;
i = cnt & 0x03; // 求应点亮的LED号(从左到右依次为 0,1,2,3)
P0 = disp[buf[i]]; // 笔划代码送P0口
P2 = scn[i]; // 控制扫描码送P2口
cnt++;
}
#Include <REG51.H>
void delay(void)
{ unsigned int i,j,k,l;
for(i=0;i<=27000;i++)
{j++; k++;l++;};
}
void main (void)
{ unsigned char i,c[4] = {0xef,0xdf,0xbf,0x7f};// 从左往右流水
i = 0;
while(1)
{ P3 = c[i & 3];
i++;
delay();
}
}
//=========================================================================
// 实验二 用一位数码管循环显示0~9
#Include <REG51.H>
#define U8 unsigned char
code U8 tab[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28};
void delay(void)
{ unsigned int i,j,k,l;
for(i=0;i<=27000;i++)
{j++; k++;l++;};
}
void main(void)
{ U8 i;
P2_4=0;
while(1)
{ P0 = tab[i];
delay();
i++;
if(i==10) i = 0;
}
}
//=============================================================================
// 实验三 LED数码管的动态驱动
#Include <REG51.H>
#define U8 unsigned char
U8 tab[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28};
U8 scn[]={0x7f,0xbf,0xdf,0xef};//先点亮左边一个数码管
U8 buf[4]={0,0,0,0};// 显示缓冲区,开机先显示"0000"
U8 cnt = 0; // 扫描计数
void main(void)
{ EA = 1; // 允许中断
TMOD = 0x01; // 设定时器0为模式1(16位)
ET0 = 1; // 定时器0中断允许
TH0 = 0xee; // 晶振11.0592MHz,5mS
TL0 = 0;
TR0 = 1; // 开始计数
while(1); // 死循环,等待中断
}
void timeint(void) interrupt 1 // 定时器0中断服务程序
{ char i;
TH0 = 0xee; // 设置定时器时间常数
TL0 = 0;
i = cnt & 0x03; // 求应点亮的LED号(从左到右依次为 0,1,2,3)
P0 = tab[buf[i]]; // 笔划代码送P0口
P2 = scn[i]; // 控制扫描码送P2口
if(cnt==200)
{ cnt=0; // 到1秒钟,显示的数字加一
for(i=3;i>=0;i--)
{ buf[i]++;
if(buf[i]==10) buf[i]=0;// 加到10向前进位
else break;
}
}
cnt++;
}
//====================================================================
// 实验四 自动演奏乐曲-康定情歌
#Include <REG51.h>
#define U8 unsigned char
code unsigned int cyc[]={1800,1600,1440,1351,1200,1079,960};//音阶1-7的半周期数
code U8 tone[]={13,15,16,16,15,16,13,12,12,13,15,16,16,15,16,13,13, 13,15,16,
16,15,16,13,12,12,15,13,12,13,12,11,12,6,6,12,15,13,12,6,6,15,13,12,13,12,11,
12,6,5,6,0xff};// 乐曲《康定情歌》的简谱表
code U8 time[]={8,8,8,4,4,8,8,12,4,8,8,8,4,4,8,16,8,8,8,8,4,4,8,8,12,4,8,8,4,4, 4,4,8,24,8,24,8,24,8,16,8,8,8,4,4,4,4,8,16,8,32};// 节拍表
U8 H0,L0,cnt;
void cntint0(void) interrupt 1 // 定时器0中断用于产生音阶方波
{ TH0=H0;
TL0=L0;
P2_3=~P2_3; // P2.3是音乐信号输出脚,P2.3反相,产生方波
}
void cntint1(void) interrupt 3 // 定时器1中断用于产生节拍延时
{ cnt++; // 计数初值为0,所以不用赋值
}
void main(void)
{ U8 i,a,t;
unsigned int b;
next:TMOD=0x11;
EA=1;
ET0=1;
ET1=1;
cnt=0;
TR1=1;
i=0;
while(1)
{ t=tone[i]; // 读音调
if(t==0xff) break; // 0xff是结束符
if(t!=0) // 0 是休止符
{ b=cyc[t%10-1]; // 根据基本音阶,求出半周期数
if(t<10) b=b*2; // 若是低八度音阶,半周期数加倍
if(t>20) b=b/2; // 若是高八度音阶,半周期数减半
H0=(65536-b)/256; // 根据半周期数,计算T0初值的高字节和低字节
L0=(65536-b)%256;
TR0=1; // 启动定时器0发音
}
cnt=0;
a=time[i]; // 读节拍
while(a>cnt);
TR0=0;
i++;
for(b=0;b<1000;b++); // 稍加延时,增强节奏感
}
P2_3=1; // 关闭喇叭
while(P3_2==1); // 等待按INT键
goto next; // 重放一遍
}
//===========================================================================
// 实验五 加法计算器
#Include <REG51.H>
#define U8 unsigned char
#define key_port P1
code U8 kcode[]={0xb7,0xbe,0xde,0xee,0xbd,0xdd,0xed,0xbb,0xdb,0xeb,0xd7,0xe7};
//反转码对应键值 0 1 2 3 4 5 6 7 8 9 A B
code U8 disp[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28,0xff};
U8 buf[4]={0,0,0,0};
U8 cnt=0;
U8 scn[]={0x7f,0xbf,0xdf,0xef};// 先点亮左边一个数码管
void delay_ms(U8 ms)
{ U8 i,j;
for(i=0;i<100;i++)
{ for(j=0;j<ms;j++);};
}
U8 key(void)
{ U8 a,r;
delay_ms(20); // 延时20毫秒,消除按键抖动
if(key_port == 0xf0) goto rn;
a = key_port;
key_port = a | 0x0f;
delay_ms(20);
a = key_port;
for (r = 0;r <= 11;r++)
{ if(a == kcode[r]) break;};
if(r > 11) r = 0xff; //0xff表示无效
rn: key_port = 0xf0;
return r;
}
void main(void)
{ U8 k,i,pf; // pf为按过加号键的标志
int p,p1,p2, // p1,p2为两个加数,p为和
TMOD = 0x01; // 设定时器0为模式1(16位)
TH0 = 0xee; // 晶振11.0592MHz,5mS
TL0 = 0;
TR0 = 1; // 开始计数
EA = 1; // 允许中断
ET0 = 1; // 定时器0中断允许
key_port = 0xf0;
pf = 0; // 清除加号标志
p = 0;
delay_ms(20);
while(1) // 循环
{ if (key_port != 0xf0)
{ k = key();
if (k < 10)
{ if((p1==0)&&(p2==0))for(i=0;i<=3;i++) buf[i] = 0;//清空显示缓冲区
else for(i=1;i<=3;i++) buf[i-1]=buf[i];// 数字左移一位
buf[3] = k;// 在个位显示刚按的数字
if(pf==0) p1 = p1 * 10 + k;
else p2 = p2 * 10 + k;
}
else
{ if(pf == 1)
{ p = p1 + p2;
p1 = 1000;
for(i=0;i<3;i++)
{ buf[i] = p / p1;
p = p - p1 * buf[i];
p1 = p1 / 10;
}
buf[3] = p;
p = 0;
p1 = 0;
p2 = 0;
pf = 0;
}
else
{ pf = 1;
p2 = 0;
for(k=0;k<=3;k++) buf[k] = 0;
}
}
while(key_port != 0xf0);// 等待按键抬起
delay_ms(20);
while(key_port != 0xf0);
}
}
}
void timeint(void) interrupt 1 // 定时器0中断服务程序
{ unsigned char i,s;
TH0 = 0xee; // 设置定时器时间常数
TL0 = 0;
i = cnt & 0x03; // 求应点亮的LED号(从左到右依次为 0,1,2,3)
P0 = disp[buf[i]]; // 笔划代码送P0口
P2 = scn[i]; // 控制扫描码送P2口
cnt++;
}
版权与免责声明:凡本网注明“来源:智能制造网”的所有作品,均为浙江兴旺宝明通网络有限公司-智能制造网合法拥有版
展开全部