这篇学习笔记虽然看起来很水,毕竟红外避障和PWM在之前的学习笔记里都写过了,但这次确实是我耗时最久的一次作业。
用软件实现PWM真是一个深渊巨坑…
首先是由于小车的方向函数的运作方式是切换运动状态,而我们用PWM的目的是要使小车在执行主函数时的运动速度始终保持我们设定的值,因此我们在一个周期中让电机停转的时候就不能只是简单的调用一个stop函数,而是要先将此刻小车的运动状态记录下来,以用来在下一个周期开始时使小车恢复原先的运动状态。我刚开始想将这个用于记录的函数写进中断程序里以方便以后写程序好直接移植,结果出现了各种各样的逻辑错误…后来发现最简单的方法就是在每次小车改变运动状态后直接记录,虽然代码看起来臃肿了许多,但逻辑变得清晰了不少。
在解决了第一个问题后,信心满满的将我的程序烧录到小车里,然后我发现我的小车就像得了脑血栓似的,你永远不知道他会在什么时候将哪行命令执行多长时间,又会在什么时候突然罢工…后来我发现(只是猜测)这是因为你永远不知道中断程序会在你的主程序执行到哪一步时忽然跳出来,他有可能在你的方向函数执行到一半时突然执行中断程序导致你的方向没有顺利改变,也可能在你的记录函数记录运动状态之前突然中断使记录发生错误…总之就是非常恶心人。于是我干脆直接在执行每个方向函数之前都重置一边定时器,在使我的代码又胖了一圈后终于解决了问题…
当然还有许多其他各种各样的小问题,比如中断程序导致Delay函数的延时参数形同虚设啦,因为各种函数的逻辑冲突导致小车抽风啦,总之,历经千辛万苦,我终于是将这么简单的一个功能搞定了…突然感觉自己好菜啊…
下面是被我改到和我的身材一样臃肿的代码(包含方向函数的头文件direction我就不往出列了)
#include <REGX52.H>
#include "direction.h"
#include "cd.h"
#define u8 unsigned char
#define u16 unsigned int
sbit BZL=P2^0 ;
sbit BZR=P2^1 ;
u8 iw=1;
u16 time_cnt=0;
u16 freq=100; //PWM输出频率
u16 duty_cycle=20; //占空比
void Timer0Init(void)
{
TMOD &= 0xF0;
TMOD = 0x01;
TL0 = 0xA4; //定时器设定为0.1ms
TH0 = 0xFF;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}