嵌入式学习小组
直播中

李兰英

7年用户 206经验值
私信 关注

STC15单片机需要注意哪些事项?

STC15F2K61S2芯片是51芯片的升级版,51上的定义配置,也可以在15上面使用。为什么我会这么说呢,因为等到我们想51芯片掌握精通了之后,再去接触430、STM32或者是更高级的芯片的时候我们就会发现,我们设置每个IO***不会像51和15那样直接就可以使用。

回帖(3)

刘思思

2019-10-14 16:01:16
这是应为随着芯片等级的提高芯片功能就会提高,但是一个芯片就只有那些引脚。像430、STM32或者更高的芯片他们就用一个引脚有多个功能(就像越是高等的人才,他们的技能绝不是单一的,不能固步自封,只有将多技能基于一身,成为全面型人才,成功才会出其不意的找上门来)。所以,越高级的芯片每次使用IO口的时候都要选择设置一下,有的还有设置定时器是输出时间更为精确。

    芯片配置:(1)3个定时器。(2)3个外部中断、2个串行口、1个SPI中断、CCP/PWM/PCA中断(3)3路硬件I2C (4)4个串行接口、2个SPI接口(5)内部自带晶振(这个高天宇说过了)(6)大容量1024字节内RAM数据存储器(7)1个时钟/机器周期,增强型8051内核,速度比8051快7~12倍。(8)IAP可以在线仿真,直接方便我们我们检测出错误。

    下面我要讲一下我在制作中设计的定时器、串口、PWM和我所遇到的知识和解决小方法。
    (1)首先我们讲一下定时器。STC15F2K61S2芯片有3个定时器(这个地方很坑),Datasheets上面说过15芯片有5个定时器,结果我用了一个晚上的时间调试定时器3怎么也调不出来,第二天打电话给STC公司询问,他们告诉我STC15F2K61S2只有定时器0、1、2.(我当时就泪奔了)。不过辛亏我打了个电话,要不就在这个地方死扣了,你们也要注意,如果怎么做还是有问题的时候,就要咨询一下官方了,绝不能在一个地方死扣,要灵活解决问题。
     每个定时器有4个模式,以定时器0为例。定时器0模式0为自动重装,模式1为16位不可重装模式,模式2为8位自动重装模式,模式3为不可屏蔽中断16位自动重装载,实时操作系统用节拍定时器。我们要根据自己的需要选择模式。
1.每次我们配置定时器的时候首先设置TCON来选择哪个定时器,如果我们设置定时器0的话就让TCON中的TR0=1使定时器0中断打开。
2.选择TMOD定时器工作模式(1个是定时器、一个是计数器)这个在TMOD中的C/T中选择。如果C/T = 1为定时器,相反为计数器。
3.给TL0和TH0赋初值具体赋值要看你选择的模式。如果你选择的是自动重装模式,你再进定时器的时候就不用自动重新装初值了,因为他会自动生成。如果不是自动重装模式,那么切记再次进入定时器的时候一定要重新赋值。
4.IE = 1中断允许寄存器打开。(这个方面一定要记得写,如果不写那么定时器虽然打开却没有被允许是无法工作的。)
5.AUXR 这是辅助寄存器,在这里我们可以选择1T模式还是12T模式。(这里我给大家扩展一下,8051上面一个机器周期是又12个时钟周期组成,所以每个时钟周期的时间是1/选择晶振的时间,而机器周期就是12*1/12M的时间,这就是所谓的12T模式。如果是1T模式的话,就是一个机器周期就是一个时钟周期,那么一个机器周期的时间就是1/选择晶振的时间。所有运行时间大大缩短,执行效率大大提高。)
6.最后是EA = 1是总中断打开。

举报

阮薇

2019-10-14 16:01:23
这是定时器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)万用表测试电压的多少,这是用于硬件检测。这些只是我暂时用到的方法以后遇到更好的方法一定告诉大家,也希望你们如果有更好的方法告诉我。

  
举报

王华

2019-10-14 16:01:25
    经过这一个月的鏖战STC杯拉下了帷幕。在这里我真的要谢谢郭老师、高天宇、刘显超。正如NBA说的那样“比赛是5个人的”,我们一个人是做不出来的,是需要团队协作的力量才能克服一切困难。我们不需要英雄主义,我们只要团队协作。郭老师让我学会了解决问题最重要的不是你有多努力,而是你有没有好的解决问题的思路。遇到问题不慌不忙,按着思路解决问题。谢谢,希望这些对你们有用。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分