资源描述
实验1-P1口交通信号灯设计-硬件和程序设计参考
硬件电路如下图所示:
实验时可以任选一列的红黄绿灯,比如选第一列,则A接电源正极+5V,可以用单片机的口线控制a\b\c\d端分别为低电平时就可以控制第一列的相应等的亮灭. 本程序中P1.0接绿灯(a端)0, P1.1接黄灯(b端), P1.2接红灯(c端).
程序如下:
/*本程序中P1.0接绿灯(a端)0, P1.1接黄灯(b端), P1.2接红灯(c端)*/
#pragma sfr /* 特殊功能能寄存器声明 */
void delay() /* 灯延时子函数定义,具体时间在实验中进行调整 */
{ int i,j;
for(i=0;i<500;i++)
{for(j=0;j<500;j++);} }
void main() /* 主函数*/
{
IMS=0XCC; /*内部存储器容量切换寄存器设置,必须有 */
IXS=0X00; /*内部扩展RAM 容量切换寄存器,必须有 */
PM1.0=0; PM1.1=0; PM1.2=0; /* 口线P1.0\P1.1\P1.2模式为输出模式*/
while(1) /* 当为1时,条件为真,一直循环 */
{P1.0=0; P1.1=1; P1.2=1; /*输出高电平灯不亮,低电平灯亮, 此时绿灯亮*/
delay();/*绿灯亮延时*/
P1.0=1; P1.1=0; P1.2=1; /*输出高电平灯不亮,低电平灯亮, 此时黄灯亮*/
delay();/*黄灯亮延时*/
P1.0=1; P1.1=1; P1.2=0; /*输出高电平灯不亮,低电平灯亮, 此时红灯亮*/
delay();/*红灯亮延时*/
} }
思考: 1 黄灯闪烁怎样修改程序? 2 各个灯亮灭的时间不一样又怎样改变程序? 3 同学们可以撇开这个程序,发挥自己的想象,自己编出自己的不同的信号灯功能?
4 用定时器来实现延时又怎样来修改程序?
5 灯延时子函数可以编写成延时时间可变的吗? 怎样来改变呢?
实验3-定时器数字时钟试验-秒表设计-硬件和程序设计参考
硬件设计参考:
参考程序如下:
#pragma sfr /* 特殊功能寄存器声明*/
#pragma di /*禁止所有中断(总中断)函数声明,相当于IE=0 */
#pragma ei /* 所有中断允许的总中断允许函数定义,相当与IE=1*/
#pragma interrupt INTTM000 TIME_INTTM000
/*后面定义的中断服务程序声明,这个中断服务程序就是本实验的定时器比较匹配中断的*/
unsigned char LED_light[10]={0xfc,0x18,0x6e,0x5e,0x9a,0xd6,0xf6,0x1c,0xfe,0xde};
/* 数码管显示的字形码,请和硬件连接相对应*/
unsigned char i; /*中断产生次数*/
void delay(int i) /*动态扫描件间隔*/
{
while(i--); /*循环i次,就是靠软件来延时,就是软件延时*/
}
void hd_init() /*硬件初始化子函数*/
{
PM1=0; /*P1口(8根口线),驱动数码管八段二极管,故定义为输出 */
PU1=0; /* 为增加驱动能力,设置为内部上拉*/
PM5.0=0; /* 定义为输出,控制其中一个数码管的公共端,控制整个这个数码管的*/
/*的亮灭,和另外一个P5.1引脚控制另一个数码管的亮灭,二者交替亮灭实现扫描显示*/
PU5.0=0; /*为增加驱动能力,设置为内部上拉*/
PM5.1=0; /* 定义为输出,控制其中一个数码管的公共端,控制整个这个数码管的*/
/*的亮灭,和另外一个P5.1引脚控制另一个数码管的亮灭,二者交替亮灭实现扫描显示*/
PU5.1=0; /*为增加驱动能力,设置为内部上拉*/
CR000=0x9000; /*设置捕捉次数,达到捕捉次数即产生中断*/
TMC00=0X0C; /*模式寄存器设置,请同学们预习这样设置是什么含义*/
PRM00=0X02; /*计数时钟选择,请同学们预习这样设置是什么含义*/
TOC00=0; /*禁止输出,请同学们预习这样设置是什么含义*/
TMIF000=0; /*中断请求,请同学们预习这样设置是什么含义*/
TMMK000=0; /*中断屏蔽,请同学们预习这样设置是什么含义*/
TMPR000=1; /*中断优先级,请同学们预习这样设置是什么含义*/
}
void main (void) /*主函数 */
{ unsigned num10,num; /* 定义秒表十位和个位变量*/
DI(); /* 关总中断开关,相当于IE=0,*/
IMS=0XCC; /* 存储器切换设置*/
IXS=0X00; /*存储器切换设置*/
hd_init(); /*调用硬件初始化子函数,进行硬件初始化 */
EI(); /*开总中断开关,相当于IE=1*/
while(1) /*主函数中,不断进行循环地进行数码秒表的十位和个位扫描显示 */
{ num10=i/10; /*计数次数取整,取出十位显示数值*/
num=i%10; /*计数值取余,取出个位显示数值*/
P5.0=1; /*十位显示制止*/
P5.1=0; /*个位显示允许*/
P1=LED_light[num]; /*秒表的数码管的个位显示数据送出,仅进行个位显示*/
delay(100); /*动态扫描件的个位显示时间间隔*/
P5.0=0; /* */
P5.1=1; /* */
P1=LED_light[num10]; /*秒表的数码管的十位显示数据送出,仅进行十位显示*/
delay(100); /*动态扫描件的十位显示时间间隔*/
}
}
__interrupt void TIME_INTTM000() /*中断服务程序定义 */
{ i++; /*计数次数加一*/ }
/*中断服务程序中仅仅对定时时间,例如这里是1秒的时间到了做一个累加,即累加有多少*/
/*个1秒了,即有多少秒了,因为上面的比较寄存器设置的个数就是1秒的计数次数,它是*/
/*根据1秒时间除以参考时钟得到的 */
思考:
1怎样实现PPG功能?
2 怎样实现方波输出?
以下是老师对上面程序设置的一些说明,请同学们参考:
CR000=0x9000; /*设置捕捉次数,达到捕捉(比较)次数即产生中断*/
时钟来源是内部时钟,固定为8M,P74,高速内置振荡器,这里的fRH=8MHz,
在配合看P158--159,PRM00预分频模式寄存器,………
PRM00=0X02; /*计数时钟选择,请同学们预习这样设置是什么含义*/
0X02=0000 0010 ,即:PRM001=1,PRM000=0,
计数脉冲的频率:f=fPRS/28 =8M/=8*106/256=31250Hz
计数脉冲的周期:T= 1/f = 1/31250s,即记一个数的时间,那么1s钟应该记多少个数(脉冲)呢?
1s钟应该记数为:1 / T = 1/(1/f)=31250 = 0x7A12 , 即应该设置CR000=0x7A12
反算一下,若设置CR000=0x9000,fPRS应该为多少? fPRS = 0x9000*28 =9437184=9.4M
TMC00=0X0C; /*模式寄存器设置,请同学们预习这样设置是什么含义*/ P155
0X0C = 0000 1100 ,TMC003=1,TMC002=1,TM00和CR000匹配时进入清零&启动模式,
TMC001=0,反转定时器输出(TO00)的条件:TM00与CR000匹配或TM00与CR010匹配
OVF00=0,把此位清零,表示从头开始,开始计数,并且此次计数还没溢出。
TOC00=0; /*禁止输出,请同学们预习这样设置是什么含义*/ P157
OSPT00=0 ,在所有模式下(单脉冲输出模式除外),不要将该位设置为1。如果该位为1,则将TM00 清零并启动。
OSPE00=0 ,连续脉冲输出模式
TOC004=0, CR010 与TM00 匹配时TO00 引脚输出控制,禁止反转操作
LVS00=0, LVR00 =0,TO00 引脚输出状态设置,无变化
TOC001=0, CR000 与TM00 匹配时TO00 引脚输出控制,禁止反转操作
TOE00=0,TO00 引脚输出控制,禁止输出 (TO00 引脚输出恒为低电平)
TMIF000=0; /*中断请求,请同学们预习这样设置是什么含义*/
IF0H.6 =0 , p134
INTTM000: TM00 与 CR000 匹配(指定比较寄存器),TI010 引脚有效沿检测(指定捕捉寄存器),P124
TMMK000=0; /*中断屏蔽,请同学们预习这样设置是什么含义*/
MK0H.6=0,P135 表示开屏蔽,
TMPR000=1; /*中断优先级,请同学们预习这样设置是什么含义*/
PR0H.6=1 ,表示设置为低优先级,由于只是一个中断,这样就可以了。
思考,中断还需要那些设置?
PSW,P137――P138
EGP和EGN 呢? 需要设置吗?P134,P136
请修改为如下:可能不做修改调试也没问题.
(建议,不修改请同学们也可以试试,因为单片机手册上(教材上)的有些东西不一定很清楚,而真正的东西要靠调试过程中去理解,就是先为TMC00=0X00;然后再TMC00=0X0C;)
TMC00=0X00;
CR000=0x7A12; /*设置捕捉次数,达到捕捉次数即产生中断*/
PRM00=0X02; /*计数时钟选择,请同学们预习这样设置是什么含义*/
TOC00=0; /*禁止输出,请同学们预习这样设置是什么含义*/
TMIF000=0; /*中断请求,请同学们预习这样设置是什么含义*/
TMMK000=0; /*中断屏蔽,请同学们预习这样设置是什么含义*/
TMPR000=1; /*中断优先级,请同学们预习这样设置是什么含义*/
TMC00=0X0C; /*模式寄存器设置,请同学们预习这样设置是什么含义*/
实验4-PWM电机试验-仅上升再停下又上升,而无缓慢下降-硬件和程序设计参考
硬件电路参考如下:
程序参考如下:
#pragma sfr
#pragma di
#pragma ei
#pragma interrupt INTTM000 TIME_INTTM000
unsigned char temp=50;
void hd_init() /* 本实验需要的硬件初始化
{
CR000=0x1A12; /*TM00定时器/计数器,做间隔定时器而且中断的时间
TMC00=0X00; /*TM00定时器/计数器停止操作(计数),为下面进行控制寄存器设置
PRM00=0X02; /*预分频率模式寄存器设置TM00计数的输入时钟
TOC00=0; /*禁止TM00定时器/计数器的输出引脚(P01)输出
TMIF000=0; /*对INTTM000中断标志清0
TMMK000=0; /*解除TM00定时器/计数器的中断屏蔽
TMPR000=1; /*设置TM00定时器/计数器的中断为低优先级
TMC00=0X0C; /*设置TM00定时器为CR000与TM00匹配时清0并启动TM00计数
PM1.5=0; /*设置TOH0/P1.5引脚为输出,是PWM波输出的要求
PM1.6=1;
TMHMD0=0X09; /*设置H0在PWM模式下工作,并且启动H0计数,开始工作
}
void main (void)
{
DI(); /*关总中断开关
IMS=0XCC;
IXS=0X00;
hd_init(); /* 调用本实验需要的硬件初始化子函数(程序)
EI(); /*打开总中断开关
CMP00=250; /*占空比周期设置
CMP10=50; /*占空比高电平设置,配合周期就形成了占空比的设置
TMHE0=1; /*启动H0开始工作
while(1); /*在主程序这里什么也不干,仅等待TM00中断而改变CMP10,高电平的值,
}
__interrupt void TIME_INTTM000()
/*TM00定时计数器的CR000和TM00匹配中断服务程序
{ TMHE0=0; /*停止H0
temp=temp+10; /*中间变量值,改变,加10每次
if(temp>250) /*到达最高占空比时,重新对中间变量赋初值50,重新开始
{temp=50;}
CMP10=temp; /*中间变量的值最终是送给占空比设置寄存器,而不断改变占空比
TMHE0=1;} /* 占空比改变后,重新启动H0开始
现象是速度慢慢上去,然后停下来,再上去,再停下来,不断循环。
思考:怎样实现速度慢慢上去,然后慢慢停下来, 不断循环呢?
(这也是本次实验的目的.),下面列出参考答案:请同学们实验时作为参考:修改程序如下:
........
unsigned char temp=50; /*定义中间变量,不断改变占空比
int dc_motor_sheng=1; /*定义上升和下降的过渡中间变量,为1应该上升,为0下降
...............
__interrupt void TIME_INTTM000()
/*TM00定时计数器的CR000和TM00匹配中断服务程序
{ TMHE0=0; /*停止H0
if(dc_motor_sheng=1) /*进入中断后,判断是该增加占空比还是该减小占空比
{temp=temp+10; /*上升时,先增加高电平的时间
if(temp>250) /*判断是否上升到比周期值大
{temp=temp-10; /*如果比周期值大,则减10,保持上一中断中的值
dc_motor_sheng=0; /*同时给下降标志值
}
}
else /*不是该上升,就是该下降了
{temp=temp-10; /*下降了,则中间变量值不断减10
if(temp<50) /*下降到设定的最小占空比了吗?
{temp=temp+10; /*下降到设定的最小占空比时,加10,保持上一中断中的值
dc_motor_sheng=1; /*同时给该上升标志值
}
}
CMP10=temp; /*中间变量的值最终是送给占空比设置寄存器,而不断改变占空比
TMHE0=1;} /* 占空比改变后,重新启动H0开始
思考:这里是用TM00做间隔定时器和H0工作在PWM方式下来实现的,能用软件延时取代TM00定时来实现吗?
实验2-外部中断程序设计-中断按键按下次数计数数码管显示-硬件和程序设计参考
硬件电路参考如下:
程序参考如下:
#pragma sfr
#pragma interrupt INTP0 LED_INTP0 /* 定义使用INTP0中断,中断函数名LED_INTP0*/
#pragma di /*禁止使用中断功能声明*/
#pragma ei /*允许使用中断功能声明*/
/*数码管编码数组*/
unsigned char LED_light[10]={0x30,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x3F};
unsigned char j=0; /*按键次数变量*/
void hdinit() /*硬件初始化*/
{
PM1=0; /*P1口输出数码管字型码,所以设置为输出*/
PU1=0XFF; /*由于P1口直接驱动数码管显示,为增大驱动,设置为内部上拉*/
PM12.0=0; /*P12.0口线要作为中断多功能,设置为输出和内部上拉 */
PU12.0=1;
PIF0=0; /*中断请求标志,没有中断请求*/
PMK0=0; /*中断屏蔽标志,允许中断*/
PPR0=1; /*中断优先级,低优先级*/
EGP.0=1; /*与EGN组合,上升沿有效*/
EGN.0=0;
}
void main (void)
{
DI(); /*首先做准备,禁止中断*/
IMS=0XCC;
IXS=0X00;
hdinit();
EI(); /*准备完成,允许中断*/
while(1)
{ /*啥也不干,就等待中断,仅是在这个实验中使用中断,实际不是这样/*
}
}
__interrupt void LED_INTP0() /*中断函数*/
{ P1= LED_light[j]; /*P1赋值,数码管显示相应数值*/
j++; /*按键次数加一*/
if(j==10) /*如果按键次数达到十次,按键计数归0*/
{j=0;} }
思考: 如果用两位数码管,从0—99循环计数又该怎样设计硬件和软件呢?
实验5-AD转换程序设计-用电位器控制直流电机转速-硬件和程序设计参考
硬件设计参考如下:
程序参考如下:
/*本程序功能是用电位器转动来控制直流电动机的转速
/*具体为:直流电机的转速用H0产生的PWM波来控制。
/*由A/D转换器的ANI0通道采集电位器的电压,用得到的数字量来改变CMP10占空比的高电平值,
/*从而改变占空比,周期不变,这样直流电机的转速不断随电位器的转动而改变
/*思考:用TM50替代H0产生PWM波形控制电机,在程序上和硬件上怎样改变?
#pragma sfr
#pragma di /*禁止使用中断功能声明*/
#pragma ei /*允许使用中断功能声明*/
#pragma interrupt INTAD MOTOR_INTAD /*声明A/D转换结束中断服务函数*/
void hd_init() /* 本实验需要的硬件初始化
{ /***** 先中断相关的SFR寄存器设置*****/
ADIF=0; //中断标志清0
ADMK=0; //A/D中断不屏蔽,允许A/D中断条件之一
ADPR=1; //中断优先级
/*****再A/D相关的寄存器设置*****/
ADCS=0; //A/D转换总开关禁止
ADCE=1; //允许比较器工作
/*注意ADM的第5~1位(FR2~FR0、LV1和LV0)设置A/D转换时间的,采用默认值,影响很小或不影响。
ADPC=0; //端口功能配置,模拟/数字,选择ANI0/P2.0-ANI7/P2.7为A/D转换端口
//但我们只用到了ANI0/P2.0,考虑只设置一个不影响其它的应该怎样设置?
PM2.0=1; //端口设置为输入功能,必须配合上面的ADPC的设置
ADS=0; //通道选择,选择ANI0通道
/*****用H0实现PWM输出的相关寄存器设置*****/
TMHMD0=0X49; //二进制为:0100 1001,依次为:0停止H0计数,100选择计数时钟,
/*10选择H0为PWM功能,0定时器输出默认为低电平,1允许定时器输出
CMP00=255; //设置H0输出PWM波形的周期
CMP10=50; //设置占空比的初始高电平初值为50
PM1.5=0; /*H0的输出端口设置为输出,以输出PWM波形,控制直流电机的转速
}
void main (void)
{ DI(); /*关总中断开关
IMS=0XCC; /*内部存储器(RAM和ROM)容量切换的设置,对0547内部存储器是固定的,
/*设置也固定为CCH
IXS=0X00; /*内部扩展RAM容量切换的设置,对0547内部RAM是固定的,设置也固定为00H
hd_init(); /* 调用本实验需要的硬件初始化子函数(程序)
TMHE0=1; /*启动H0开始工作,开始在P1.5输出PWM波形
ADCS=1; //A/D转换总开关打开,开始对ANI0通道的输入模拟量进行A/D转换
EI(); /*打开总中断开关
while(1); /*在等待,到中断去执行相应处理
}
__interrupt void MOTOR_INTAD() /*A/D转换结束的中断服务函数
{ DI(); /*关总中断开关
ADIF=0; //中断标志清0
ADCS=0; //A/D转换总开关禁止
CMP10=ADCRH; //控制占空比
ADCS=1; //A/D转换总开关打开,开始对ANI0通道的输入模拟量进行A/D转换
EI(); /*打开总中断开关
}
请同学们在课后对照硬件认真阅读程序,不懂的地方请认真阅读相关部分的端口功能章节讲解的存储器含义和相关的软件设计章节!
并思考上面程序中的两个思考题目,准备上实验课时提问,并在实验时除了按上面的实验外,争取再按上面思考的内容修改程序,重新进行实现!
- 239 -
展开阅读全文