/**********************
舵机控制PWM/按键控制/LED显示
V1.0版
******************************************/
#include "STC15W40XXX.H"
#include "intrins.h"
//定义主时钟
#define FOSC 33177600UL
#define T1000Hz (FOSC / 12 / 1000)
#define CCP_S0 0x10 //P_SW1.4
#define CCP_S1 0x20 //P_SW1.5
//************** PWM8 变量和常量以及IO口定义 ***************
//******************** 6通道8 bit 软PWM ********************
sbit P_PWM6 = P3^4; // 舵机1 PWM定义IO
sbit P_PWM5 = P3^5; // 舵机2 PWM定义IO
sbit P_PWM4 = P3^6; // 舵机3 PWM定义IO
sbit P_PWM3 = P2^0;
sbit P_PWM2 = P2^1;
sbit P_PWM1 = P2^2;
sbit LED1 = P2^3;
sbit LED2 = P2^4;
sbit LED3 = P2^5;
sbit LED4 = P2^6;
sbit LED5 = P2^7;
sbit LED6 = P1^0;
sbit Key1=P5^5; //单个舵机转动
sbit Key2=P5^4; //全部舵机转动
sbit Key3=P1^7; //复位按键
bit Reset=0;
uint P1_11us=0;
uint cnt;
uint value;
uchar K1_cont=0;
uchar K2_cont=0;
unsigned char j;
unsigned char KeySta[3] = { 1, 1, 1 }; //全部按键的当前状态
unsigned char backup[3] = { 1, 1, 1 }; //按键值备份,保存前一次的值
uint Ptem_angle[6]={90,90,90,90,90,90}; //6个舵机临时存储角度(在0-180内)
uint SetP_angle[6] ={90,90,90,90,90,90}; //6个设定舵机转动角(0-180)(11us*(45-225)=0.5ms -2.5ms
//--------------------
void UartInit(); [url=]//9600bps@33.1776MHz[/url]
void Timer0Init(); //Timer0 set
void PCATimerInit(); //Timer0 set
void Key_scan(); //按键扫描函数
void Key_Function(); //按键功能函数
void LDE_Shew(); //LED显示函数
void Motor_Run(); //LED显示函数
void Delay500ms() [url=]//@33.1776MHz[/url]
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 64;
j = 9;
k = 179;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/**********************************************/
void main()
{
PCATimerInit(); //PCA定时器初始化
Timer0Init(); //定时器0初始化
UartInit(); //串口初始化
EA = 1; //打开总中断
Delay500ms();
while(1)
{
Key_Function();
LDE_Shew();
}
}
/********************** Timer0 11us中断函数 ************************/
//为什么要定义11us的中断,因为20ms的周期信号控制舵机转动,0.5-2.5中,只有2ms时间高电平控制0-180的角度。
//因此转动1度时,需要11us的时间(一次中断产生),180度需要1980us,约2MS,例如转动90度是1.5MS高和18.5的低,
//一个周期20ms产生1800次的中断,其中90+45=135次中断为高,1800-135=1665次为低。循环得到结果
void timer0 (void) interrupt 1
{
switch (K1_cont)
{
case 0: P_PWM1=0; break;
case 1: Motor_Run(); P_PWM2= P_PWM3= P_PWM4= P_PWM5= P_PWM6= 0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM1 = 1; } else { P_PWM1 = 0; } break;
case 2: Motor_Run(); P_PWM1=P_PWM3=P_PWM4=P_PWM5=P_PWM6= 0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM2 = 1; } else { P_PWM2 = 0; } break;
case 3: Motor_Run(); P_PWM1 =P_PWM2=P_PWM4=P_PWM5=P_PWM6= 0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM3 = 1; } else { P_PWM3 = 0; } break;
case 4: Motor_Run(); P_PWM1 =P_PWM2=P_PWM3=P_PWM5=P_PWM6= 0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM4 = 1; } else { P_PWM4 = 0; } break;
case 5: Motor_Run(); P_PWM1 =P_PWM2=P_PWM3=P_PWM4=P_PWM6=0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM5 = 1; } else { P_PWM5 = 0; } break;
case 6: Motor_Run(); P_PWM1=P_PWM2=P_PWM3= P_PWM4= P_PWM5=0;
if(P1_11us<=Ptem_angle[K1_cont-1]) { P_PWM6 = 1; } else { P_PWM6 = 0; } break;
default: break;
}
}
//PCA定时器中断
void PCA_isr() interrupt 7 using 1
{
CCF0 = 0; //清中断标志
CCAP0L = value;
CCAP0H = value >> 8; //更新比较值
value += T1000Hz;
if (cnt-- == 0)
{
cnt = 2000; //记数1000次
SBUF=0XFF;
}
Key_scan();
}
//*************************************************************************
//UART 串口中断
void Uart() interrupt 4 using 1
{
if (RI)
{
RI = 0;
}
if (TI)
{
TI = 0; //
}
}
void Key_scan()//按键扫描函数
{
uchar j;
static uchar keybuf[3] = { 0xFF, 0xFF, 0xFF }; //按键扫描缓冲区
//将3 个按键值移入缓冲区
keybuf[0] = (keybuf[0] << 1) | Key3;
keybuf[1] = (keybuf[1] << 1) | Key2;
keybuf[2] = (keybuf[2] << 1) | Key1;
//消抖后更新按键状态
for (j=0; j<3; j++) // 3 个按键,所以循环 3 次
{
if ((keybuf[j] & 0xFF) == 0x00) //连续 3次扫描值为 0,即 24ms 内都是按下状态时,可认为按键已稳定的按下
{
KeySta[j] = 0;
}
else
if ((keybuf[j] & 0xFF) == 0xFF)
{ //连续 4次扫描值为 1,即16ms 内都是弹起状态时,可认为按键已稳定的弹起
KeySta[j] = 1;
}
}
}
void Key_Function()
{
static bit i=0;
for (j=0; j<3; j++) //依次检测按键
{
if (backup[j] != KeySta[j]) //检测按键动作
{
if (backup[j] != 0) //按键按下时执行动作
{
switch (j)
{
case 0: K2_cont=0; K1_cont++; if(K1_cont>=7) K1_cont=0;
break;
case 1:
if(!i)
{
SetP_angle[K1_cont-1]-=10;
if(SetP_angle[K1_cont-1]<=45)
{
i=!i;
}
}
else
{
SetP_angle[K1_cont-1]+=10;
if(SetP_angle[K1_cont-1]>=170)
{
i=!i;
}
}
break;
case 2:
break;
default: break;
}
}
backup[j] = KeySta[j]; //更新前一次的备份值
}
}
}
//
//////LEDf显示函数
void LDE_Shew()
{
switch (K1_cont)
{
case 0: LED1=LED2=LED3=LED4=LED5=LED6=1; break;
case 1: LED1=LED2=LED3=LED4=LED5=LED6=1; LED1=0; break;
case 2: LED1=LED2=LED3=LED4=LED5=LED6=1; LED2=0; break;
case 3: LED1=LED2=LED3=LED4=LED5=LED6=1; LED3=0; break;
case 4: LED1=LED2=LED3=LED4=LED5=LED6=1; LED4=0; break;
case 5: LED1=LED2=LED3=LED4=LED5=LED6=1; LED5=0; break;
case 6: LED1=LED2=LED3=LED4=LED5=LED6=1; LED6=0; break;
default: break;
}
}
void Motor_Run()
{
P1_11us++; //一次中断,自加一次
if (P1_11us>1800) //20ms执行以下程序
{
P1_11us=0; //清0
if(Ptem_angle[K1_cont-1]>=(SetP_angle[K1_cont-1]+40))
{
Ptem_angle[K1_cont-1]--; //自加一次角度,电机缓慢运行,在设定的角度内反复转动,如0-90度
}
else
{
Ptem_angle[K1_cont-1]++;
}
}
}
//******************串口初始化
void UartInit(void) [url=]//9600bps@33.1776MHz[/url]
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR &= 0xFB; //定时器2时钟为Fosc/12,即12T
T2L = 0xB8; //设定定时初值
T2H = 0xFF; //设定定时初值
AUXR |= 0x10; //启动定时器2
ES=1; //允许串口中断
}
//定时器T0用作脉冲发生器,定时11us
void Timer0Init(void) //11微秒@33.1776MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x8F; //设置定时初值
TH0 = 0xFE; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //中断允许
}
//PCA定时器设置 定时1MS
void PCATimerInit()
{
ACC = P_SW1;
ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=0
P_SW1 = ACC; //(P1.2/ECI, P1.1/CCP0, P1.0/CCP1, P3.7/CCP2)
CCON = 0; //初始化PCA控制寄存器
//PCA定时器停止 清除CF标志 清除模块中断标志
CL = 0; //复位PCA寄存器
CH = 0;
CMOD = 0x00; //设置PCA时钟源
//禁止PCA计数器中断
value = T1000Hz;
CCAP0L = value;
CCAP0H = value >> 8; //初始化PCA模块0
value += T1000Hz;
CCAPM0 = 0x49; //PCA模块0为16位定时器模式
CR = 1; //PCA定时器开始工作
cnt = 0;
}
|