|
数据类型 | | | | sbit | |
| | signed char | | | | unsigned char | | | | signed short | | | | unsigned short | | | | signed int | | | | unsigned int | | | | signed long | | | | unsigned long | | | | float | | | 0.175494E-38~0.402823E+38 | sfr | | | | sfr16 | | | |
51基本数据类型
unsigned char data *p=0x00; 访问内部RAMunsigned char xdata *q=0x01; 访问外部RAMunsigned char code *x=0x02; 访问ROM
C51程序设计实例
例1:把存放在程序存储区3800H-3805H单元中的6个常数读到内部RAM的20H开始的单元。
#include<reg51.h>
unsignedchar code *p=0x3800;
unsignedchar data *q=0x20;
voidmain (void)
{
unsigned char i;
for(i=0;i<6;i++)
{
*(q+i)=*(p+i);
}
}
例2:从20H单元开始存放32个带符号数,要求统计出大于0、小于0和等于0的个数并存放在单片机内部RAM的60H,61H,62H单元中。
#include<reg51.h>
chardata *p=0x20;
unsignedchar data *q=0x60;
voidmain(void)
{
for(i=0;i<32;i++)
{
if(*(p+i)>0)
{
*q=*q+1;
}
else if (*(p+i)<0)
{
*(q+1)=*(q+1)+1;
}
else
{
*(q+2)=*(q+2)+1;
}
}
}
例3:将片外数据存储器中7000H-70FFH单元全部清零。
#include<reg51.h>
unsignedchar xdata *p=0x7000;
voidmain (void)
{
unsigned char i;
for(i=0;i<256;i++)
{
*(p+i)=0;
}
}
例1:P1口接八个共阴极发光二极管,试编写程序令发光二极管循环点亮。
#include<reg51.h>
voiddelay(unsigned int n) 延时n(ms)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<120;j++);
}
voidmain (void)
{
unsigned char i;
for(i=0;i<8;i++)
{
P1=(1<<i); 左循环,左移
delay(250); 延时250ms,代表n
}
}
例2:电路如下图。8051的P1.0、P1.1、P1.2、P1.3分别接入四支发光二极管VD0、VD1、VD2、VD3,P3.0、P3.1、P3.2、P3.4分别接入四支开关S0、S1、S2、S3。
开关断开,对应的发光二极管亮。
开关闭合,对应的发光二极管灭。
#include<reg51.h> (见课本)
voidmain (void)
{
while(1)
{
switch(P3&0x0f)
{
case 0x01: P1=P1|0x01;break;
case 0x02: P1=P1|0x02;break;
case 0x04: P1=P1|0x04;break;
case 0x08: P1=P1|0x08;break;
default:;
}
}
}
中断
#include<reg51.h>
void init(void)//中断初始化
{
IT0=1; //设为下降沿触发
EX0=1; //开外部中断0
EA=1;//开总中断
}
void main(void)
{
init();
While(1);
}
void ex0() interrupt 0 //中断子函数
{
P1=0xff;
IE1=0;
}
例:通过/INT0的下降沿实现数码管增计数,/INT1的下降沿实现数码管减计数。计数范围0-9
#include<reg51.h>
unsignedchar LED[10]={0x3f,0x06,....};
unsignedchar i;
voidmain(void)
{
IT0=1;IT1=1;
EX0=1;EX1=1;EA=1; (固定套路)
while(1);
}
voidex0() interrupt 0 允许中断后执行interrupt程序,当为/INT0中断时,对应向量0,选择该程序进行;若为……
{
if(i<9)
{
P0=LED[++i];
}
else;
}
voidex1() interrupt 2
{
if(i>0)
{
P0=LED[--i];
}
else;
}
中断与查询相结合的方式进行外部中断
voidex0() interrupt 0
{
switch(P1&0x0f)
{
case 0x01: DV1();break;
case 0x02: DV2();break;
case 0x04: DV3();break;
case 0x08: DV4();break;
default:;
}
IE0=0; //低电平触发中断
}
定时器
方式0
例:应用定时器T0产生1ms定时,并使P1.0输出周期为2ms的方波,方式0。已知晶振震荡频率为6MHz。
TH0=(213-500)/25 (初值的计算与写入)
TL0=(213-500)%25
#include<reg51.h>
sbitled=P1^0;(定义接口P1.0,使C51单片机识别接口为P1.0)
voidmain (void)
{
TMOD=0x00;
TH0=(213-500)/25;
TL0=(213-500)%25;
TR0=1;
while(1)
{
if(TF0==1)
{
led=~led;
TH0=(213-500)/25;
TL0=(213-500)%25; 四句话
TF0=0;
}
else;
}
}
方式1
例:用定时器T1产生25Hz方波,由P1.0输出,采用查询方式进行控制,方式1。已知晶振震荡频率为12MHz。
#include<reg51.h>
sbitled=P1^0;
voidmain(void)
{
TMOD=0x10;
TH1=(216-20000)/28;
TL1=(216-20000)%28;
TR1=1;
while(1)
{
if(TF1==1)
{
led=~led;
TH1=(216-20000)/28;
TL1=(216-20000)%28;
TF1=0;
}
else;
}
}
例:利用定时器T0工作方式1,实现一个发光二极管以1s亮灭闪烁。12MHz晶振。
(使用中断的方式,定时时间超过单片机所允许的时间)
#include<reg51.h>
sbitled=P1^0;
unsignedchar num;
voidmain(void)
{
TMOD=0x01;
TH0=(216-50000)/28;
TL0=(216-50000)%28; 六句话
ET0=1;EA=1;TR0=1;
while(1)
{
if(num==20)
{
led=~led;
num=0;
}
}
}
voidT0() interrupt 1
{
num++;
TH0=(216-50000)/28;
TL0=(216-50000)%28;
}
方式2
例:用定时器T1,工作方式2计数,要求每计满156次,将P1.7取反。
#include<reg51.h>
sbitled=P1^7;
voidmain(void)
{
TMOD=0x60;
TH1=28-156;
TL1=28-156;
TR1=1;
while(1)
{
if(TF1==1)
{
led=~led;
TF1=0;
}
}
}
(见课本,方式0、1、2的综合)
方式3(只适用于T0)
例:应用T0方式3,分别设定200μs和400μs定时并使P1.0和P1.1分别产生周期为400μs和800μs方波。晶振6MHz。采用中断控制方式。
#include<reg51.h>
sbitled1=P1^0;
sbitled2=P1^1;
voidmain(void)
{
TMOD=0x03;
TH0=28-100; //200μs
TL0=28-200; // 400μs
ET0=1;ET1=1;EA=1;
TR0=1;TR1=1;
while(1);
}
voidtime0() interrupt 1
{
TL0=28-200;
led2=~led2;
TF0=0;
}
void time1() interrupt 3
{
TH0=28-100;
led1=~led1;
TF1=0;
}
串行口
例1:请编写在数码管上循环显示0-9这10个数字的程序。串行通信方式0,定时器间隔1s。
#include<reg51.h>
unsignedchar led[10]={0x03,….};
unsignedchar num,I;
voidmain(void)
{
TMOD=0x01;
TH0=(216-50000)/28;
TL0=(216-50000)%28;
TR0=1;
ET0=1;
EA=1;
SCON=0x00;
while(1)
{
if(num==20)
{
num=0;
SBUF=led[i++];
if(i==10)
{
i=0;
}
}
}
}
voidT0() interrupt 1
{
num++;
TH0=(216-50000)/28;
TL0=(216-50000)%28;
TF0=0;
}
例2:根据电路图,编写从16位扩展口读入10个字节数据,并把它们转存到内部RAM的20H~29H中。S/L=0并行置入16位数据;S/L=1允许串行移位输出
#include<reg51.h>
unsignedchar data *p=0x20;
unsignedchar i,j;
void main(void)
{
SCON=0x10; //方式0
for(i=0;i<5;i++)
{
P1&=0xfe; //P1.0置0
P1|=0x01; //P1.0置1
for(j=0;j<2;j++)
{
while(!RI); //等待数据接收完成
*p++=SBUF; //将数据缓存区中接收到的数据给了20H
RI=0; //响应中断后该标志位必须及时清零,为下一次做准备
}
}
}
第一个for循环是为了分5次接收字节,每次接收16位数,也就是2个字节;第二个for循环是将一次接收的2个字节转存RAM
先让P1.0=0,是为了置入16位数;置入后让P1.0=1,是为了允许串行移位输出
C51拓展
存储器拓展
例,下图采用的是译码法还是片(线)选法?74LS139、74LS373起到什么作用?2#芯片的寻址范围是什么?执行unsigned char xdata *r22= 0x4000;语句后,r22变量中的值将存储于哪一个芯片中?
下图采用的是译码法。
74LS139作用是地址译码。
2000H~3FFFH。
存储于3#芯片中。
38译码器,数电中的知识点,eg. CBA—001—Y1口,从而对应2#芯片
010—Y2口,从而对应3#芯片
P2.7P2.6 P2.5
只有这三种选法,因为外部RAM使能必须保证/CE为低电平
外部
I/O拓展
例题:利用74LS244作为输入口接8路开关,读取开关状态,并将读取状态通过74LS273驱动发光二极管显示出来。
#include <reg51.h>
unsignedchar xdata *p=0xbfff;(分析)
unsignedchar xdata *q=0x7fff;
unsignedchar buffer;
voidmain(void)
{
buffer=*p;
*q=buffer;
}
输入缓冲,输出锁存
常用作输入拓展的芯片:74LS244、74LS373
注:74LS244是8位三态门,当/1G、/2G均为低电平时,允许输入数据;否则,为高阻态。
74LS373的/E=0时才允许输入
常用作输出拓展的芯片:74LS377、74LS273
注:74LS377的E=0时才可将数据打入锁存器
74LS273的CLK=0时才可将数据打入锁存器
(具体讲解想见课本)
A/D拓展
1111 1110 1111 1***
P2.0 P0.2 P0.1 P0.0
例题:设有一个8路模拟量输入的巡回检测系统,采样数据依次存放在外部RAM 2000H-2007H单元中,要求采用中断方式。
#include <reg51.h>
unsignedchar xdata *p=0xfef8; //一定要写正确,对通道的选择
unsignedchar xdata *q=0x2000;
unsignedchar num=1;
voidmain(void)
{
IT0=0;
EX0=1;
EA=1;
*p=0x00; //写什么都行,需要送出地址
while(1);
}
voidad() interrupt 0
{
*q=*p;
p++;
q++;
num++;
if(num==8)
{
EX0=0;
EA=0;
}
*p=0x00; //写什么都行,需要送出地址
IE0=0;
}
|
|