这是定时器0的初始化void Time0Init(void) //500微秒@24.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器0开始计时
EA=1;
}
我编写飞控程序的时候借鉴了匿名四轴的程序,学到了他的一个变成思想,我想分享给大家。原来我们编写程序的时候基本上将程序全部都写到了main函数中,定时器只是起到辅助的作用。而匿名的程序是将主要的程序全部写到定时器中,每2ms进行一次姿态解算,每4ms进行一次PID运算。这样是程序运行起来效率更高,各司其职,不需要等一条指令执行完,再去执行下一条指令。还有我们选择定时器的时候一定要看他们的数据手册,不要盲目的凭借自己的经验。数据手册给你的是正确的(当然不包括定时器3)。
(2)串口设置。这里我先帮大家解除一个误区,这个也误导我好长时间。要不是因为芯片功能太有限了,和郭老师告诉我,我还是不会了解。每次我们设置串口的时候,要设置串口中断来接受数据和发送数据。因此我们要产生定时器,我以为每个串口要消耗一个定时器,后来在做飞控的时候定时器实在不够用了,郭老师告诉我我才将两个串口公用一个定时器,因为定时器在串口中只是产生波特率的作用。两个串口可以共同接收和共同发送,但是一个接收、一个发送就出现问题了,这个我要再进一步解决。还有,串口发送的时候有测忙标志,因为芯片运行速度没有那么快,当要发送的时候,程序还在测忙阶段,这样数据就发送不出去了。当我们以后数据发送不出去的时候不妨看一下是不是这个地方有问题。
1.我们要选择波特率,两方数据通信的时候波特率必须一样,否则无法接受到数据。一般大家设置为115200和9600
2.SCON串口控制设置,通过SM0、SM1选择工作方式有8位波特率可变、9位波特率、9位波特率可变
3.AUXR选择定时器是否分频,这样可以是串口高效率工作,不用高速度执行低速的事情。
4.TH0、TL0这是在设置定时器产生的波特率。
5.ES = 1是CPU总中断开放。
6.SBUF是数据包,8位。接收数据和发送数据都是并行发送8位数据。串行一个一个字节发送。
这是串口2的初始化void InitUART2(void)
{
P_SW2 &= ~S2_S0; //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
S2CON = 0x50; //8位数据,可变波特率
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = (65536 - (FOSC/4/BAUD2)); //设置波特率重装值
T2H = (65536 - (FOSC/4/BAUD2))>>8;
AUXR |= 0x10; //启动定时器2
IE2 = 0x01; //使能串口2中断
EA = 1;
}
(3)硬件PWM产生。这个PWM是8位的PWM,当然我们可以选择7位、6位的PWM,不过这样我们产生的PWM的可调范围就很小了。一开始我们产生PID用8位的PWM控制电机旋转,因为8位可以产生0~256的数值,但是电调范围必须为243到230这样我们只有12个档可调。导致我们的飞机在倾斜到一定角度后才发现倾斜,纠正过来幅度又很大,导致飞机一直摇摆。而且,我们产生PWM的频率必须要求在50Hz,八位的PWM的频率 = PCA时钟输入源频率/256。PCA时钟输入源可以从以下8种中选择一种:SYSclk,SYSckl/2,SYSclk/4,SYSclk/6,SYSclk/8,SYSclk/12,定时器0的溢出,ECI/P1.2输入。如果产生50Hz的频率要PCA时钟输入源频率为12800.这时我们的SYSclk为24M除以12的不出来12800数值。所有我们只有两个方案,方案一、为用定时器0溢出,也就是说要产生78us的定时器。但是问题就是我们已经将定时器0作为心跳功能了,所有我们不能再将定时器0作为SYSclk了,所以方案一基本告废。方案二、我们就想到用ECI/P1.2输入,这是一个外部时钟接口。我们只需用另一个单片机产生78us的定时器输入到ECI中就可以产生50Hz的频率。当我们解决了产生8位的50Hz的PWM时,我们就可以控制电机的控制。但是问题有出来了,还是刚才说的8位的PWM调节范围太小,导致飞机一直在颤抖。因此我们想是不是可以产生16位的PWM。郭老师教导我,让我用数据手册带的16位软硬结合的方法调节PWM,这样我们就产生了16位0~1000的PWM。我们PWM产生的波形更加的连续,可是因为16位的PWM是软硬结合的方法产生。就因为我们用到串口中断读取陀螺仪MPU6050和无线数据模块发送来的数据,使得我们产生的PWM在时间上出了干扰,使得PWM也时常有跳变,这个跳变是我们无法解决的。
1.CMOD是PCA工作模式寄存器。刚才说过PCA用8种模式,在CMOD中用CPS2、CPS1、CPS0就是选择这8个工作模式
2.CCON是PCA控制寄存器。因为CCON中CF是PCA计数器阵列溢出标志位。CR是PCA计数器阵列运行控制位。该位通过软件置位,用来启动PCA计数器阵列计数。改为通过软件清零,用来关闭PCA计数器。
3.CCAPMn是选择功能寄存器。
4.低8位CL和高8位CH,PCA计数通过CL和CH来计数。一般情况下先清0.
5.CCAPnL和CCAPnH 在PWM模式时,他们用来控制输出的占空比。这样我们就可以通过给CCAPnL和CCAPnH就可以赋值。这个和8051有很大的区别,也是硬件PWM的优点。因为PWM产生是通过占空比产生的。而占空比又是通过高电平占用总周期的时间叫占空比。比如我们产生20ms周期也就是50Hz的PWM,高电平可以是1~19ms。
6.PCA_PWMn选择6~8位的PWM。
7.AUXR1/P_SW1是选择外围设备切换控制器寄存器。这是STC15的最大优势。15的功能比8051强大的多,所以功能就更加的多。这样会有你想用的功能但是被其他的功能占用着。这就体现优势的时候了。我们可将功能对应的引脚切换成没有功能占用的引脚。在这里PWM模块也是这样的。PWM有3个模块我们可以在这个寄存器中选择模块来选择对应的引脚。模块0连接到P1.1/CCP0或P3.5/CCP0_2或P2.5/CCP0_3或/P1.2/ECI;模块1连接到P1.0/CCP1或P3.6/CCP1_2或P2.6/CCP1_3或P3.4/ECI_2;模块2连接到P3.7/CCP2或P3.7/CCP2_2或P2.7/CCP2_3或P2.4/ECI_3;
以下是PWM初始化的例程 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)
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=1 CCP_S1=0
// ACC |= CCP_S0; //(P3.4/ECI_2, P3.5/CCP0_2, P3.6/CCP1_2, P3.7/CCP2_2)
// P_SW1 = ACC;
//
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=1
// ACC |= CCP_S1; //(P2.4/ECI_3, P2.5/CCP0_3, P2.6/CCP1_3, P2.7/CCP2_3)
// P_SW1 = ACC;
CCON = 0; //初始化PCA控制寄存器
//PCA定时器停止
//清除CF标志
//清除模块中断标志
CL = 0; //复位PCA寄存器
CH = 0;
CMOD = 0x02; //设置PCA时钟源
//禁止PCA定时器溢出中断
PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
CCAP0H = CCAP0L = 0x20; //PWM0的占空比为87.5% ((100H-20H)/100H)
CCAPM0 = 0x42; //PCA模块0为8位PWM模式
PCA_PWM1 = 0x40; //PCA模块1工作于7位PWM
CCAP1H = CCAP1L = 0x20; //PWM1的占空比为75% ((80H-20H)/80H)
CCAPM1 = 0x42; //PCA模块1为7位PWM模式
PCA_PWM2 = 0x80; //PCA模块2工作于6位PWM
CCAP2H = CCAP2L = 0x20; //PWM2的占空比为50% ((40H-20H)/40H)
CCAPM2 = 0x42; //PCA模块2为6位PWM模式
CR = 1; //PCA定时器开始工作
(4)现在我们再讲一下I2C。在我们将STM32的飞控程序移植到STC15芯片上时真是很艰难。因为STM32和STC15的运行速度是不一样的我们一开始直接照搬STM32的I2C的程序结果怎么都读取不了数据。没有办法我们只能使用8051的I2C的程序。再通过示波器一点点调试最后总算出来了。经过调试I2C我总结了一下。首先,我们调试I2C的时候一定要看数据手册给的I2C时序。因为不同的I2C可能时序有些不同。我们在调试I2C和SPI的时候一定要按着标准的时序来调试。其次,我们调试I2C的时候用到了示波器。这是个很好的工具。因为我们在调试I2C和SPI时序的时候我们不可能通过做Debug灯来看是否出现错误。所以我们通过示波器显示的波形和Datasheets给的时序比较。
解决错误小方法:(1)Debug灯,我们如果程序无法执行的时候可以做个小灯来看程序的那个部分出现错误。(2)示波器,我们在调试串口数据、I2C、SPI等数据传输的时候就可以通过示波器的显示来判断问题所在。(3)设置固定的PWM值,这是在PWM问题中通过设置固定的PWM配合着示波器来判断,这种方法在我们产生16位PWM的时候,电机1和3、电机2和4的PWM始终相同,结果我们就是通过这种方法解决了。(4)万用表测试电压的多少,这是用于硬件检测。这些只是我暂时用到的方法以后遇到更好的方法一定告诉大家,也希望你们如果有更好的方法告诉我。
这是定时器0的初始化void Time0Init(void) //500微秒@24.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器0开始计时
EA=1;
}
我编写飞控程序的时候借鉴了匿名四轴的程序,学到了他的一个变成思想,我想分享给大家。原来我们编写程序的时候基本上将程序全部都写到了main函数中,定时器只是起到辅助的作用。而匿名的程序是将主要的程序全部写到定时器中,每2ms进行一次姿态解算,每4ms进行一次PID运算。这样是程序运行起来效率更高,各司其职,不需要等一条指令执行完,再去执行下一条指令。还有我们选择定时器的时候一定要看他们的数据手册,不要盲目的凭借自己的经验。数据手册给你的是正确的(当然不包括定时器3)。
(2)串口设置。这里我先帮大家解除一个误区,这个也误导我好长时间。要不是因为芯片功能太有限了,和郭老师告诉我,我还是不会了解。每次我们设置串口的时候,要设置串口中断来接受数据和发送数据。因此我们要产生定时器,我以为每个串口要消耗一个定时器,后来在做飞控的时候定时器实在不够用了,郭老师告诉我我才将两个串口公用一个定时器,因为定时器在串口中只是产生波特率的作用。两个串口可以共同接收和共同发送,但是一个接收、一个发送就出现问题了,这个我要再进一步解决。还有,串口发送的时候有测忙标志,因为芯片运行速度没有那么快,当要发送的时候,程序还在测忙阶段,这样数据就发送不出去了。当我们以后数据发送不出去的时候不妨看一下是不是这个地方有问题。
1.我们要选择波特率,两方数据通信的时候波特率必须一样,否则无法接受到数据。一般大家设置为115200和9600
2.SCON串口控制设置,通过SM0、SM1选择工作方式有8位波特率可变、9位波特率、9位波特率可变
3.AUXR选择定时器是否分频,这样可以是串口高效率工作,不用高速度执行低速的事情。
4.TH0、TL0这是在设置定时器产生的波特率。
5.ES = 1是CPU总中断开放。
6.SBUF是数据包,8位。接收数据和发送数据都是并行发送8位数据。串行一个一个字节发送。
这是串口2的初始化void InitUART2(void)
{
P_SW2 &= ~S2_S0; //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
S2CON = 0x50; //8位数据,可变波特率
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = (65536 - (FOSC/4/BAUD2)); //设置波特率重装值
T2H = (65536 - (FOSC/4/BAUD2))>>8;
AUXR |= 0x10; //启动定时器2
IE2 = 0x01; //使能串口2中断
EA = 1;
}
(3)硬件PWM产生。这个PWM是8位的PWM,当然我们可以选择7位、6位的PWM,不过这样我们产生的PWM的可调范围就很小了。一开始我们产生PID用8位的PWM控制电机旋转,因为8位可以产生0~256的数值,但是电调范围必须为243到230这样我们只有12个档可调。导致我们的飞机在倾斜到一定角度后才发现倾斜,纠正过来幅度又很大,导致飞机一直摇摆。而且,我们产生PWM的频率必须要求在50Hz,八位的PWM的频率 = PCA时钟输入源频率/256。PCA时钟输入源可以从以下8种中选择一种:SYSclk,SYSckl/2,SYSclk/4,SYSclk/6,SYSclk/8,SYSclk/12,定时器0的溢出,ECI/P1.2输入。如果产生50Hz的频率要PCA时钟输入源频率为12800.这时我们的SYSclk为24M除以12的不出来12800数值。所有我们只有两个方案,方案一、为用定时器0溢出,也就是说要产生78us的定时器。但是问题就是我们已经将定时器0作为心跳功能了,所有我们不能再将定时器0作为SYSclk了,所以方案一基本告废。方案二、我们就想到用ECI/P1.2输入,这是一个外部时钟接口。我们只需用另一个单片机产生78us的定时器输入到ECI中就可以产生50Hz的频率。当我们解决了产生8位的50Hz的PWM时,我们就可以控制电机的控制。但是问题有出来了,还是刚才说的8位的PWM调节范围太小,导致飞机一直在颤抖。因此我们想是不是可以产生16位的PWM。郭老师教导我,让我用数据手册带的16位软硬结合的方法调节PWM,这样我们就产生了16位0~1000的PWM。我们PWM产生的波形更加的连续,可是因为16位的PWM是软硬结合的方法产生。就因为我们用到串口中断读取陀螺仪MPU6050和无线数据模块发送来的数据,使得我们产生的PWM在时间上出了干扰,使得PWM也时常有跳变,这个跳变是我们无法解决的。
1.CMOD是PCA工作模式寄存器。刚才说过PCA用8种模式,在CMOD中用CPS2、CPS1、CPS0就是选择这8个工作模式
2.CCON是PCA控制寄存器。因为CCON中CF是PCA计数器阵列溢出标志位。CR是PCA计数器阵列运行控制位。该位通过软件置位,用来启动PCA计数器阵列计数。改为通过软件清零,用来关闭PCA计数器。
3.CCAPMn是选择功能寄存器。
4.低8位CL和高8位CH,PCA计数通过CL和CH来计数。一般情况下先清0.
5.CCAPnL和CCAPnH 在PWM模式时,他们用来控制输出的占空比。这样我们就可以通过给CCAPnL和CCAPnH就可以赋值。这个和8051有很大的区别,也是硬件PWM的优点。因为PWM产生是通过占空比产生的。而占空比又是通过高电平占用总周期的时间叫占空比。比如我们产生20ms周期也就是50Hz的PWM,高电平可以是1~19ms。
6.PCA_PWMn选择6~8位的PWM。
7.AUXR1/P_SW1是选择外围设备切换控制器寄存器。这是STC15的最大优势。15的功能比8051强大的多,所以功能就更加的多。这样会有你想用的功能但是被其他的功能占用着。这就体现优势的时候了。我们可将功能对应的引脚切换成没有功能占用的引脚。在这里PWM模块也是这样的。PWM有3个模块我们可以在这个寄存器中选择模块来选择对应的引脚。模块0连接到P1.1/CCP0或P3.5/CCP0_2或P2.5/CCP0_3或/P1.2/ECI;模块1连接到P1.0/CCP1或P3.6/CCP1_2或P2.6/CCP1_3或P3.4/ECI_2;模块2连接到P3.7/CCP2或P3.7/CCP2_2或P2.7/CCP2_3或P2.4/ECI_3;
以下是PWM初始化的例程 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)
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=1 CCP_S1=0
// ACC |= CCP_S0; //(P3.4/ECI_2, P3.5/CCP0_2, P3.6/CCP1_2, P3.7/CCP2_2)
// P_SW1 = ACC;
//
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=1
// ACC |= CCP_S1; //(P2.4/ECI_3, P2.5/CCP0_3, P2.6/CCP1_3, P2.7/CCP2_3)
// P_SW1 = ACC;
CCON = 0; //初始化PCA控制寄存器
//PCA定时器停止
//清除CF标志
//清除模块中断标志
CL = 0; //复位PCA寄存器
CH = 0;
CMOD = 0x02; //设置PCA时钟源
//禁止PCA定时器溢出中断
PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
CCAP0H = CCAP0L = 0x20; //PWM0的占空比为87.5% ((100H-20H)/100H)
CCAPM0 = 0x42; //PCA模块0为8位PWM模式
PCA_PWM1 = 0x40; //PCA模块1工作于7位PWM
CCAP1H = CCAP1L = 0x20; //PWM1的占空比为75% ((80H-20H)/80H)
CCAPM1 = 0x42; //PCA模块1为7位PWM模式
PCA_PWM2 = 0x80; //PCA模块2工作于6位PWM
CCAP2H = CCAP2L = 0x20; //PWM2的占空比为50% ((40H-20H)/40H)
CCAPM2 = 0x42; //PCA模块2为6位PWM模式
CR = 1; //PCA定时器开始工作
(4)现在我们再讲一下I2C。在我们将STM32的飞控程序移植到STC15芯片上时真是很艰难。因为STM32和STC15的运行速度是不一样的我们一开始直接照搬STM32的I2C的程序结果怎么都读取不了数据。没有办法我们只能使用8051的I2C的程序。再通过示波器一点点调试最后总算出来了。经过调试I2C我总结了一下。首先,我们调试I2C的时候一定要看数据手册给的I2C时序。因为不同的I2C可能时序有些不同。我们在调试I2C和SPI的时候一定要按着标准的时序来调试。其次,我们调试I2C的时候用到了示波器。这是个很好的工具。因为我们在调试I2C和SPI时序的时候我们不可能通过做Debug灯来看是否出现错误。所以我们通过示波器显示的波形和Datasheets给的时序比较。
解决错误小方法:(1)Debug灯,我们如果程序无法执行的时候可以做个小灯来看程序的那个部分出现错误。(2)示波器,我们在调试串口数据、I2C、SPI等数据传输的时候就可以通过示波器的显示来判断问题所在。(3)设置固定的PWM值,这是在PWM问题中通过设置固定的PWM配合着示波器来判断,这种方法在我们产生16位PWM的时候,电机1和3、电机2和4的PWM始终相同,结果我们就是通过这种方法解决了。(4)万用表测试电压的多少,这是用于硬件检测。这些只是我暂时用到的方法以后遇到更好的方法一定告诉大家,也希望你们如果有更好的方法告诉我。
举报