/*----------------------------------------------------------*/
/* */
/* 中颖SH88F2051/SH88F4051无线遥控智能小车DEMO程序 */
/* */
/* 功能 :使用中断方式动态接收遥控信号,软件模拟解码, */
/* 硬件 PWM 控制小车运行。 */
/* */
/* A键:小车前进时加速,后退时减速,共有5挡速度 */
/* 供调节,2挡快慢正转,2挡快慢反转,1挡 */
/* 停止运转。 */
/* */
/* B键:功能同上,小车前进时减速,后退时加速, */
/* 共有5挡速度供调节,2挡快慢正转,2挡 */
/* 快慢反转,1挡停止运转。 */
/* */
/* C键:在运行时,按下小车左转,松开恢复正常运 */
/* 行,小车停止时无效。 */
/* */
/* D键:在运行时,按下小车右转,松开恢复正常运 */
/* 行,小车停止时无效。 */
/* */
/* */
/* 入口 :指定 P3.0 为无线遥控接收信号输入 */
/* 出口 :键值存 Key 中,A键=1, B键=2, C键=3, D键=4 */
/* */
/* 资源 :占用 T0 定时中断, 作为20ms定时采样 */
/* 占用 PWM 中断, 刷新 PWM 输出 */
/* 占用 INT0 中断, 作为电机运转方向动态切换 */
/* */
/* */
/* CPU : SH88F2051/SH88F4051 */
/* 晶振 : 片内16.6MHz高精度RC振荡器 */
/* 作者 : 许意义 */
/* ID : LAOXU */
/* 版本 : V1.0 */
/* 日期 : 2011.8.21 */
/* */
/*----------------------------------------------------------*/
// 关于硬件 PWM 驱动直流电机 DEMO 示范程序声明:
//
// 程序编写的比较烦琐, 可精简很多字节,但没有进行优化,本意是用该程序构架
// 扩充成10位硬件 PWM 输出,实现高精度的动态 PWM 电机驱动实时控制,以适应
// 21ic《两轮自平衡小车DIY》的实际需求。
//
#include <DEFINE51.H>
#include <SH88F4051.H>
#define Tsmp_T0 0x10000-27667 // 20ms T0 16位向上计数计数器/定时器, 重装入定时常数
#define Tsmp_T1 0x100-138 // 100us T1 8位自动重装入定时常数
extern unsigned char Key; // 外部键值输入,A键=1,B键=2,C键=3,D键=4
sbit MA = P4^0; // H输出高,L输出低
sbit MB = P4^1; // H输出高,L输出低
sbit MC = P4^2; // H输出高,L输出低
sbit MD = P3^7; // H输出高,L输出低
//sbit C1 = P3^5; // H输出有效,L输出关闭
//sbit C2 = P3^2; // H输出有效,L输出关闭
#define Left_Motor_Forward() {MA = 1; MB = 0;} // 左电机正转
#define Left_Motor_Reverse() {MA = 0; MB = 1;} // 左电机反转
#define Right_Motor_Forward() {MC = 0; MD = 1;} // 右电机正转
#define Right_Motor_Reverse() {MC = 1; MD = 0;} // 右电机反转
#define Left_Motor_Stop() {MA = 0; MB = 0;} // 左电机停止
#define Right_Motor_Stop() {MC = 0; MD = 0;} // 右电机停止
#define Key_Stop_Time 10 // 键盘松开延时确定时间,20ms的倍数
bit Left_Motor_Flag; // 左电机运行停止标记,0-->运行, 1-->停止
bit Right_Motor_Flag; // 右电机运行停止标记,0-->运行, 1-->停止
volatile signed char PWM_Vx=0; // PWM 输出缓冲区
unsigned char code Char_PWM[]={0xf0, 0xb0, 0, 0xb0, 0xf0}; // 5挡 PWM 输出速度值
void interrupt_time0(void) interrupt 1 using 2 // 20ms定时中断
{ static unsigned char Time0_Count=0;
static bit Key_Flag=0;
TL0 = LO_BYTE(Tsmp_T0); // 装入T0定时器的初值, 延时20ms
TH0 = HI_BYTE(Tsmp_T0); // T0 16位向上计数计数器/定时器, 使用片内16.6MHz片内RC振荡器, 12分频
Time0_Count++;
if((Key == 1) && (!Key_Flag))
{ if(++PWM_Vx >= 3)
{ PWM_Vx = 2; // 正转加速限制
}
Time0_Count = 0;
Key_Flag = 1;
}
else if((Key == 2) && (!Key_Flag))
{ if(--PWM_Vx <= (-3))
{ PWM_Vx = (-2); // 反转加速限制
}
Time0_Count = 0;
Key_Flag = 1;
}
else if((Key == 3) && (PWM_Vx != 0))
{ Left_Motor_Flag = 0; // 左电机运行
Right_Motor_Flag = 1; // 右电机停止运行
Time0_Count = 0;
Key_Flag = 1;
}
else if((Key == 4) && (PWM_Vx != 0))
{ Left_Motor_Flag = 1; // 左电机停止运行
Right_Motor_Flag = 0; // 右电机运行
Time0_Count = 0;
Key_Flag = 1;
}
else
{ if(Time0_Count>=Key_Stop_Time)
{ Left_Motor_Flag = 0; // 左电机运行
Right_Motor_Flag = 0; // 右电机运行
Time0_Count = 0;
Key_Flag = 0;
}
}
Key = 0;
}
void car_PWM_int(void) interrupt 12 using 1
{ PWMD = Char_PWM[PWM_Vx+2]; // PWM输出实时更新
PWMCON &= Bin(11111101); // 清除 PWM 周期计数器溢出标志 PWMIF
}
void car_motor_dir(void) interrupt 0 using 1
{ if(PWM_Vx > 0) // 如果 PWM_Vx值 > 0, 电机正转
{ if(Left_Motor_Flag == 0)
Left_Motor_Forward() // 左电机标记值=0, -->左电机正转
else
Left_Motor_Stop() // 左电机标记值=1, -->左电机停止
if(Right_Motor_Flag == 0)
Right_Motor_Forward() // 右电机标记值=0, -->右电机正转
else
Right_Motor_Stop() // 右电机标记值=1, -->右电机停止
}
else if(PWM_Vx < 0) // 如果 PWM_Vx值 < 0, 电机反转
{ if(Left_Motor_Flag == 0)
Left_Motor_Reverse() // 左电机标记值=0, -->左电机反转
else
Left_Motor_Stop() // 左电机标记值=1, -->左电机停止
if(Right_Motor_Flag == 0)
Right_Motor_Reverse() // 右电机标记值=0, -->右电机反转
else
Right_Motor_Stop() // 右电机标记值=1, -->右电机停止
}
else // 如果 PWM_Vx值 = 0, 电机停止
{ Left_Motor_Stop(); // -->左电机停止
Right_Motor_Stop(); // -->右电机停止
}
}
void init(void)
{
P1 = Bin(11111111);
P3 = Bin(01011011); // 置 MA,MB,MC,MD,C1,C2 输出为L,关闭L293输出
P4 = Bin(00000000);
//-----------------------------------
// PxM0n PxM1n 说 明
// 0 0 准双向
// 0 1 推挽输出
// 1 0 输入(高阻)
// 1 1 开漏输出
P1M0 = Bin(00000000);
P1M1 = Bin(00000000);
P3M0 = Bin(00000000); // 设置 MA,MB,MC,MD,C1为推挽输出, C2为准双向
P3M1 = Bin(10100000);
P4M0 = Bin(00000000);
P4M1 = Bin(00000111);
P3 |= Bin(00000100); // 置C2(INT0)为H,以便使用INT0下降沿中断触发
CLKCON = Bin(00001100); // Fsys = Foscs,使用片内16.6MHz片内RC振荡器
TCON1 = Bin(00000000); // 设置系统时钟12分频作为T0的时钟源,系统时钟12分频作为T1的时钟源
TMOD = Bin(00100001); // 设定T0的工作模式为1, 16位向上计数计数器/定时器,
// 设定T1的工作模式为2,8位自动重载向上计数计数器/定时器
TL0 = LO_BYTE(Tsmp_T0); // 装入T0定时器的初值, 延时20ms
TH0 = HI_BYTE(Tsmp_T0); // T0 16位向上计数计数器/定时器, 使用片内16.6MHz片内RC振荡器, 12分频
TL1 = 138; //Tsmp_T1; // 装入T1定时器的初值, 延时100us
TH1 = 138; //Tsmp_T1; // 8位自动重装入, 使用片内16.6MHz片内RC振荡器, 12分频
PWMD = 0x00;
PWMP = 0xff;
PWMCON = Bin(10110001); // 设置 PWM 输出
IT0 = 1; // INT0 下降沿触发方式
PT1L = 1; // 设置 T1定时器为高级中断
PX0L = 1; // 设置 INT0为高级中断
IPL1 |= Bin(00100000); // 设置 PPWML为高级中断
IEN1 |= Bin(00100000); // PWM 允许中断
EX0 = 1; // INT0 充许中断
ET0 = 1; // 定时器0允许中断
ET1 = 1; // 定时器1允许中断
TR0 = 1; // 启动定时器0
TR1 = 1; // 启动定时器1
EA = 1; // 开中断
}
void main(void)
{ init(); // 中断初始化
while(1){ ; }
} |