申请样片:美信公司,www.maxim-ic.com,右上角有简体中文,在右边直接购买标题的下面有申请样品,点击后新页面下打开工业控制,在数据资料中找DS12CR887,在右上角的型号搜索栏中填入DS12CR887点击搜索,新网页打开后在右边有数据资料可以下载,在该页面的下面找样品与定购信息,找到DS12CR887,点击超级链接,打开新页面,在新页面下的下面下载DS12CR887-5+,点击样品,在新页面下填写资料,点击提交;一周申请一次
AD公司,www.analog.com也可以申请样品
TI公司,www.ti.com,可以一个月申请一次
While (表达式)
{语句(内部也可为空)}
特点:先判断表达式,后执行语句。
原则:若表达式不是0,即为真,那么执行语句。否则跳出while 语句。
写程序时头脑中要形成一种时序的概念,写程序控制单片机,让单片机控制外围器件,单片机按照指令的从上而下的顺序一条一条执行
一般单片机的程序要先进入一个大循环
Tab键是语句行右移,Shift+Tab是左移
While(1)就是始终进行循环
两个原则:一是大循环用While(1)加大括号,在大括号中进行总程序的循环;二是如果要程序停止在某一行,用While(1)加分号(;),程序永远不会往下执行
软件仿真:工具栏上的打印机按钮右边的按钮Start,点击后进入调试模式,
工具栏上出现的按钮,第一个按钮,RST外形的按钮是复位CPU,作用是功能复位,将指针指到程序的开始;第二个按钮,Run按钮,全速执行;第三个按钮,Halt按钮,停止按钮;第四个按钮,Step into按钮,进入函数体内部(进入子函数常用),单步执行,一条一条走;第五个按钮,Step over按钮,一次执行一个语句;黄色箭头指向当前语句,再点一下Step over按钮即执行这句程序,每执行一条指令,内部所有寄存器都会发生变化,这里可以打开菜单栏的Peripherals(硬件)下面的按钮(中断,IO端口,串行端口,定时器),这里打开IO端口的Port1(P1口),再打开菜单栏的View下面的Watch & Call Stack Window,这里选择Watch & Call Stack Window面板上的Watch#1页面,这里点击Name下面的框(或者按F2),输入要查看的变量,再回车,可以在变量上右键单击选择16进制或10进制,单步Step over一下,发现P1口的第零位勾没了,即表示为零,Watch#1页面的a的值也变了,可以设置断点,双击某一行即设置断点,再双击取消,这里在第二个a=50000处设置断点,即上一句whie(a--)执行完就停下,断点的作用是在全速执行程序时,当要执行断点所在的指令的时候程序就停下来,这里a是65535,表示a已经全减空了,全减空是0,再减一下就是65535,再点下全速Run程序又停在断点处,说明程序又进行一次循环,又到了断点处
使用仿真芯片,安装好仿真芯片89E516RD,再在Keil中进行设置,单击工具栏的Option for target按钮进行设置,点击Debug页,点击右边的Use Keil Monitor-51 Driver的Settings,选择COM口,点击OK即可,下面的可打钩的都打钩,然后确定,用仿真芯片和普通的使用单片机不一样,要先打开单片机的电源,点击按钮Start进行调试,左侧的信息框出现Connected to Monitor-51 V3.4,进行单步Step over调试,第二步看见发光二极管亮,这里走的慢,设置断点在第二个a=50000处,然后全速Run,程序走的断点处,再点二步就走到p1_1=1处即发光二极管熄灭,去掉断点全速执行发光二极管就正常执行闪烁;使用仿真芯片可以知道每一条指令如何执行,每一个变量如何变化;结束调试,先按下单片机上的复位按钮,再按下Keil软件中的按钮Start结束调试
看一下变量的情况,可以把该变量值改小点,然后调试
让发光二极管每隔500ms闪烁,单片机上右下角的复位键左侧是晶振,11.0592MHZ,单击工具栏的Option for target按钮进行设置,点击Target页,对Xtal晶振频率进行设置
在需用软件调节时间时可以将这里的晶振调节成和单片机板的晶振同样大小,这里改成11.0592
查看延时的时间,在调试状态下,左侧有sec(秒),单位是秒,程序单步走时间也在走,在发光二极管灭之前设置断点,即在p1_1=1处设置断点,全速运行一下,再看时间,这里用了488ms,我们再微调到500ms,先结束调试,再修改程序,然后编译,再调试;微妙级的可以忽略(开始调试前,sec是几百微妙,可以忽略);这里发光二极管依然是500ms闪烁,因为发光二极管的是由单片机的硬件决定的,硬件没有变化,单片机内部晶振还是11.0592MHZ,减慢或加快闪烁速度仍要通过程序来控制
仿真时间时要,单击工具栏的Option for target按钮进行设置,点击Target页,对Xtal晶振频率进行设置
#include<reg52.h>
sbit p1_1=P1^0;
unsigned int a;
void main()
{
while(1)
{
a=51000;
p1_1=0;
while(a--);
a=51000;
p1_1=1;
while(a--);
}
}
在第一个a=51000处设置一个断点,全速运行,到下面的断点第二个p1_1=1处,时间是490ms,再全速运行,到第一个a=51000处的断点,运行时间是1.107s,即运行完发光二极管灭后的时间是1.107s
每次修改完都要编译一下再调试,否则只会调试到上次程序的状态
在项目中,完全是调用子程序,主程序中完全是调用子程序
For循环如果有大括号可以不加分号,循环嵌套在最后的循环结尾处加一个分号表示该嵌套包含在上一个嵌套的里面,此时如果再写一个循环就和上面的循环没有关系了
宏定义时要把要定义的变量名写在前面,类型写在后面,结尾不用加分号
子函数在调用时要在主函数前声明,因为要为子函数分配空间,如果不分配空间,在调用时主函数会找不到子函数
调试时,要在要调试的语句的下一句设置断点,因为要看执行完该语句后的状态
在声明带参数的子函数时,要声明子函数内参数的类型,可以写参数名,也可以不写参数名,如果有多个参数,写上类型后用逗号隔开
#include<reg52.h>
#define uint unsigned int //unsigned int为正数,所以不用考虑变量为负
#define uchar unsigned char
sbit D1=P1^0;
//void delay();
void delay(uint);
void main()
{
while(1)
{
D1=0;
delay(100);
//delay();
D1=1;
delay(100);
//delay();
}
}
/*void delay()
{
uint x,y;
for(x=100;x>0;x--)
for(y=600;y>0;y--);
}*/
void delay(uint z)
{
uint x,y;
//uchar y;
for(x=z;x>0;x--)
for(y=600;y>0;y--);
}
51帮助文档在Keil文件下面的C51文件下面的HLP文件下面的C51lib.Chm
_crol_函数是循环左移函数,上面标有#include <intrins.h>,说明使用时要添加该头文件
下面又标示,unsigned char _crol_ (unsigned char c, /* character to rotate left */
unsigned char b); /* bit positions to rotate */
表示该函数返回值是unsigned char,参数中第一个是表示要移位的变量,第二个是要移动的位数
去除当前工程的文件,右键点击要删除的文件,选择Remove File
流水灯程序:
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar temp,num,num1;//因为P1口是八位的,如果定义成int型可能会出错,所以要定义成char型
sbit beep=P2^3;
void delay(uint);
void main()
{
temp=0xfe;
P1=temp;
while(1)
{
temp=_crol_ (temp,1);
delay(100);
P1=temp;
}
}
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
蜂鸣器在TX-1C型单片机实验板原理图中单片机右边锁存器下面,FM旁边电阻上面的18表示18欧姆,FM连接单片机的P2^3口;三极管有电流放大功能,三极管是压控流型的,电压控制电流的放大倍数,这里用的是三极管的开关功能,PNP型,图中的箭头应该标在下面,
三极管有三极,从左至右从上到下依次是b(基极)c(集电极)e,箭头一般在b和e之间,由e指向b(如果是NPN型也是如此,从左至右从上到下依次是bce,箭头一般在b和e之间,但箭头是由b指向e);当基极b给低电平,集电极c;蜂鸣器里面内阻极小,里面有线圈贴合铁片,接Vcc,线圈通电吸合铁片产生振动发出声音,而基极b给低电平,由c向b正向导通,PN节之间有压降,正向导通,有压降所以将c和e之间连通,即当给b低电平时相当于将c和e之间连通,反之如果b高电平,和c之间没有压降c和e之间不会导通;总结一下,给b低电平蜂鸣器响,给b高电平蜂鸣器不响
接触式继电器,开始a和b连通,当线圈给电产生磁场,把a和b的线圈吸过去,让b和c连通,见下图,继电器线圈上面连接Vcc,下面连接三极管,三极管连接单片机的P2^3口
驱动继电器方法同蜂鸣器,P2^3口给低电平,继电器工作;继电器要反向接一个发光二极管,作用是突然关闭继电器时,线圈中产生逆向感应电流,电流会反向流过,由d到e,这里接二极管电流就会流向二极管,而不会流向三极管导致bc之间的PN结击穿
课后练习:
第一个发光管以间隔200ms闪烁:
我的方法:
#include<reg52.h>
#define uint unsigned int//unsigned int为正数,所以不用考虑变量为负
#define uchar unsigned char
sbit D1=P1^0;
void delay()
{
uint i,j;
for(i=115;i>0;i--)
for(j=200;j>0;j--);
}
void main()
{
while(1)
{
D1=0;
delay();
D1=1;
delay();
}
}
课件方法:这里把频率调成11.0592MHZ
#include<reg52.h> //52单片机头文件
#define uint unsigned int //宏定义
#define uchar unsigned char //宏定义
sbit led1=P1^0; //单片机管脚位声明
void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.
{ //delay(500);大约延时500ms.
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main() //主函数
{
while(1) //大循环
{
led1=0; //点亮小灯
delay(200); //延时200毫秒
led1=1; //熄灭小灯
delay(200); //延时200毫秒
}
}
8个发光管由上至下间隔1s流动,其中每个管亮500ms,灭500ms,亮时蜂鸣器响,灭时关闭蜂鸣器,一直重复下去。
我的方法:第一步是让第一个发光二极管亮500ms,灭500ms,亮时蜂鸣器响,灭时关闭蜂鸣器,再做流水灯
再改动完程序,编译完,用STC软件时要先打开一下程序文件,然后再Download程序
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep=P2^3;
void delay(uint);
void main()
{
uchar temp;
temp=0xfe;
while(1)
{
P1=temp;
beep=0;
delay(500);
P1=0xff;
beep=1;
delay(500);
temp=_crol_(temp,1);
}
}
void delay(uint z)
{
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
8个发光管来回流动,每个管亮100ms,流动时让蜂鸣器发出"滴滴"声。
变量的定义要一起定义在函数体的前面,否则会出错
来回流动的意思是从第一个发光二极管流到第八个发光二极管后再从第八个发光二极管流到第一个发光二极管
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep=P2^3;
void delay(uint);
void main()
{
uchar temp,a;
while(1)
{
temp=0xfe;
for(a=8;a>0;a--)
{
P1=temp;
beep=0;
delay(100);
P1=0xff;
beep=1;
delay(100);
temp=_crol_(temp,1);
}
temp=0x7f;
for(a=8;a>0;a--)
{
P1=temp;
beep=0;
delay(100);
P1=0xff;
beep=1;
delay(100);
temp=_cror_(temp,1);
}
}
}
void delay(uint z)
{
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
用8个发光管演示出8位二进制数累加过程:
^ ~ (按位异或 按位取反)
我的方法:
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
void delay(uint);
void main()
{
uint a,temp;
while(1)
{
a=0x00;
for(temp=256;temp>0;temp--)
{
a++;
P1=~a;
delay(200);
}
}
}
void delay(uint z)
{
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
课件的方法:把计数值直接定义成uchar型,uchar型范围是0~255,而计数个数是256,正好是0到255共256个数,就不用循环了
#include<reg52.h> //52单片机头文件
#include <intrins.h> //包含有左右循环移位子函数的库
#define uint unsigned int //宏定义
#define uchar unsigned char //宏定义
void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.
{ //delay(500);大约延时500ms.
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main() //主函数
{
uchar a;
while(1) //大循环
{
a++;
P1=~a;
delay(200);
}
}
8个发光管间隔200ms由上至下,再由下至上,再重复一次,然后全部熄灭再以300ms间隔全部闪烁5次。重复此过程:
我的方法:先做8个发光管间隔200ms由上至下,再由下至上,再重复一次,再做然后全部熄灭再以300ms间隔全部闪烁5次
做一部分就看下硬件状况,调节一下,然后再做下一部分,如果有一部分不好使,可以注释掉其它程序,单独调试这部分,也可以单建立工程,单提出来这部分程序进行调试
我的错误片段:因为
void main()
{
uint a;
uchar temp;
while(1)
{
for(temp=2;temp>0; temp--)//总循环跳不出来
{
a=0xfe;
for(temp=8;temp>0;temp--)
{
P1=a;
delay(200);
a=_crol_(a,1);
}
a=0x7f;
for(temp=8;temp>0;temp--)//从这里出来temp的值变化了,再到总循环处,对总循环的temp造成影响,导致总循环跳不出来
{
P1=a;
delay(200);
a=_cror_(a,1);
}
}
a=0xfe;
for(temp=8;temp>0;temp--)
{
P1=a;
delay(200);
a=_crol_(a,1);
}
a=0x7f;
for(temp=8;temp>0;temp--)
{
P1=a;
delay(200);
a=_cror_(a,1);
}
a=0xff;
P1=a;
for(temp=5;temp>0;temp--)
{
delay(300);
a=0x00;
P1=a;
delay(300);
a=0xff;
P1=a;
}
}
}
正确的程序:
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
uint a;
uchar temp,untemp;
while(1)
{
for(untemp=2;untemp>0;untemp--)
{
a=0xfe;
for(temp=8;temp>0;temp--)
{
P1=a;
delay(200);
a=_crol_(a,1);
}
a=0x7f;
for(temp=8;temp>0;temp--)
{
P1=a;
delay(200);
a=_cror_(a,1);
}
}
P1=0xff;
for(temp=10;temp>0;temp--)
{
delay(300);
P1=~P1;
}
}
}
间隔300ms第一次一个管亮流动一次,第二次两个管亮流动,依次到8个管亮,然后重复整个过程:
课件的方法:
+ - * / (加 减 乘 除)
> >= < <= (大于 大于等于 小于 小于等于)
== != (测试等于 测试不等于)
&& || ! (逻辑与 逻辑或 逻辑非 )
>> << (位右移 位左移)
& | (按位与 按位或)
^ ~ (按位异或 按位取反)
利用位左移,移入第一位是零,来编写程序
#include<reg52.h> //52单片机头文件
#include <intrins.h> //包含有左右循环移位子函数的库
#define uint unsigned int //宏定义
#define uchar unsigned char //宏定义
void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.
{ //delay(500);大约延时500ms.
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main() //主函数
{
uchar a,i,j;
while(1) //大循环
{
a=0xfe; //赋初值
for(j=0;j<8;j++)
{
for(i=0;i<8-j;i++) //左移
{
P1=a; //点亮小灯
delay(200); //延时200毫秒
a=_crol_(a,1); //将a变量循环左移一位
}
a=_crol_(a,j); //补齐,方便下面的左移一位,通过列出数可以看出此步骤是必需要有的
P1=0xff; //全部关闭
a=a<<1; //左移一位让多一个灯点亮,注意左移后要重新赋给变量
}
}
}
间隔300ms先奇数亮再偶数亮,循环三次;一个灯上下循环三次;两个分别从两边往中间流动三次;再从中间往两边流动三次;8个全部闪烁3次;关闭发光管,程序停止:
一步一步做,做一步调试一步,程序中每两步之间要有空格,这样结构清楚
#include<reg52.h> //52单片机头文件
#include <intrins.h> //包含有左右循环移位子函数的库
#define uint unsigned int //宏定义
#define uchar unsigned char //宏定义
void delay(uint z) //延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.
{ //delay(500);大约延时500ms.
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main() //主函数
{
uchar a,i,j;
for(j=0;j<3;j++) //奇偶交替
{
P1=0x55; //点亮小灯
delay(300); //延时300毫秒
P1=0xaa;
delay(300); //延时300毫秒
}
for(j=0;j<3;j++) //流水灯
{
a=0xfe;
for(i=0;i<8;i++)
{
P1=a; //点亮小灯
delay(300); //延时300毫秒
a=_crol_(a,1);
}
}
P1=0xff;
for(j=0;j<3;j++) //从两边往中间流
{
P1=0x7e; //点亮小灯
delay(300); //延时300毫秒
P1=0xbd;
delay(300); //延时300毫秒
P1=0xdb; //点亮小灯
delay(300); //延时300毫秒
P1=0xe7;
delay(300); //延时300毫秒
}
P1=0xff;
for(j=0;j<3;j++) //从中间往两边流
{
P1=0xe7; //点亮小灯
delay(300); //延时300毫秒
P1=0xdb;
delay(300); //延时300毫秒
P1=0xbd; //点亮小灯
delay(300); //延时300毫秒
P1=0x7e;
delay(300); //延时300毫秒
}
P1=0xff;
for(j=0;j<6;j++) //全部闪烁
{
P1=~P1; //点亮小灯
delay(300); //延时300毫秒
}
P1=0xff;
while(1);//程序停止,把while(1)放在后面
}