Coryright@Fourmily版权声明本文档版权归属福州大学四库之家(Fourmily)所有,并保留一切权力。非经四库之家同意,任何单位及个人不得擅自摘录本文档部分或全部,违者我们将追究其法律责任。目录1.探索STC12C5A60S2指令执行速度-------------------32.探索STC12C5A60S2I/O口工作模式-----------------63.探索STC12C5A60S2定时器-------------------------84.探索STC12C5A60S2看门狗-------------------------115.探索STC12C5A60S2UART串行口通信-----------------156.探索STC12C5A60S2A/D转换------------------------247.探索STC12C5A60S2PCA/PWM功能--------------------278.探索STC12C5A60S2EEPROM的应用-------------------359.探索STC12C5A60S2内部扩展1024字节RAM的使用-----391.探索STC12C5A60S2指令执行速度STC12C5A60S2/AD/PWM系列单片机是单时钟/单周期(1T)的单片机,指令代码完全兼容传统8051,但速度快8-12倍。空口无凭,接下我们就通过下面这个实验来证明这一点:在Keil中新建一个工程,MCU模板我们采用AT89S52单片机,新建main.c文件并将其加入工程中。main.c内容:#includereg52.hsbitLED=P1^0;voidDelay_1ms(unsignedintz){unsignedintx,y;for(x=z;x0;x--)for(y=114;y0;y--);}voidmain(){for(;;){LED=1;Delay_1ms(1000);LED=0;Delay_1ms(1000);}}一个很简单的闪烁灯程序,其中的延时采用软件延时。关于Delay_1ms这个函数顾名思义是一个延时1ms的函数,在主程序中我们传入的参数是1000,所以LED灯会隔一秒闪烁一下。设置晶振11.0592MHz编译工程0Error(s),0Warning(s).调试按单步调试,并观察左侧时间,并根据现象调整Delay_1ms里面的参数,使得Delay_1ms(1000)能比较准确地延时1s。voidDelay_1ms(unsignedintz){unsignedintx,y;for(x=z;x0;x--)for(y=114;y0;y--);}上述的参数值就是我经过测试后得出来的值,将工程编译得到的HEX文件下载到单片机中观察现象,发现LED灯闪烁的比预料的快很多,这是什么原因呢?我们查找文档发现有这么一句话,STC12C5A60S2/AD/PWM系列单片机是单时钟/单周期(1T)的单片机,指令代码完全兼容传统8051,但速度快8-12倍。于是我们将Delay_1ms函数改为:voidDelay_1ms(unsignedintz){unsignedintx,y;for(x=z;x0;x--)for(y=1368;y0;y--);//114x12=1368}编译工程,将目标代码下载到单片机运行,发现LED如我们设想的隔一秒闪烁一次,看来STC12C5A60S2真的比传统的8051单片机快8-12倍。2.探索STC12C5A60S2I/O口工作模式STC12C5A60S2所有I/O口均可由软件配置成4种工作类型之一,4种类型分别为:准双向口(标准8051输出模式)、推挽输出、仅为输入(高阻)或开漏输出功能。I/O口工作类型设定(在此以P1口为例):传统I/O口模式拉电流仅为230uA,如果LED灯的阳极接到I/O口阴极接到GND,显然单片机是无法驱动LED的。同样以一个例子证明我们的推断。编写简单测试程序main.c#includereg52.hsbitLED=P1^0;voidmain(){LED=1;//点亮LED灯for(;;);}编译、下载目标代码,发现LED并没有点亮,或者说LED的亮度几乎可以忽略,说明传统的I/O口模式拉电流不足以驱动LED灯。我们将源代码稍作修改,粉色字段为新增加代码。#includereg52.hsfrP1M1=0x91;//定义P1口配置寄存器sfrP1M0=0x92;sbitLED=P1^0;voidmain(){P1M1&=~(10);//配置P1.0为推挽输出P1M0|=(10);LED=1;for(;;);}编译、下载目标代码,发现LED较之前明显亮了。3V/5V混合系统I/O口互连3.探索STC12C5A60S2定时器STC12C5A60S2系列是1T的8051单片机,为了兼容传统的8051,定时器0和定时器1复位后是传统8051的速度,既12分频,这是为了兼容传统8051。但也可以不进行12分频,实现真正的1T。T0x12:0,定时器0是传统8051速度,12分频;1,定时器0的速度是传统8051的12倍,不分频。T1x12:0,定时器1是传统8051速度,12分频;1,定时器1的速度是传统8051的12倍,不分频。这里我们以定时器T0为例,新建工程,编写测试程序main.c#includereg52.hsfrP1M1=0x91;//定义P1口配置寄存器sfrP1M0=0x92;sbitLED=P1^0;unsignedintTime=0;bitflag;voidTimer0_Init(void)//定时器0初始化{TMOD&=0xf0;TMOD|=0x02;//T0方式2TL0=0x47;//定时0.2msTH0=0x47;ET0=1;//允许T0中断TR0=1;//启动定时器}voidmain(){P1M1&=~(10);//配置P1.0为推挽输出P1M0|=(10);Timer0_Init();EA=1;for(;;){if(flag)LED=1;//点亮LEDelseLED=0;//熄灭LED}}voidTiemr0_Isr(void)interrupt1{Time++;if(Time==5000)//定时1s到{Time=0;flag=!flag;}}编译、下载目标代码,LED灯以1s间隔闪烁,说明我们的代码是正确的。现在我们修改一下代码,关闭定时器T0的12分频,粉色字段为新增加代码。#includereg52.hsfrP1M1=0x91;//定义P1口配置寄存器sfrP1M0=0x92;sfrAUXR=0x8e;//定义定时器12分频配置寄存器sbitLED=P1^0;unsignedintTime=0;bitflag;voidTimer0_Init(void)//定时器0初始化{AUXR|=(17);//置位T0x12TMOD&=0xf0;TMOD|=0x02;//T0方式2TL0=0x47;//定时0.2msTH0=0x47;ET0=1;//允许T0中断TR0=1;//启动定时器}voidmain(){P1M1&=~(10);//配置P1.0为推挽输出P1M0|=(10);Timer0_Init();EA=1;for(;;){if(flag)LED=1;//点亮LEDelseLED=0;//熄灭LED}}voidTiemr0_Isr(void)interrupt1{Time++;if(Time==5000)//定时1s到{Time=0;flag=!flag;}}编译、下载目标代码,很明显LED灯闪烁的比之前快很多。4.探索STC12C5A60S2看门狗在工业控制/汽车电子/航空航天等需要高可靠性的系统中,为了防止“系统在异常情况下,受到干扰,MCU/CPU程序跑飞,导致系统长时间异常工作”,通常是引进看门狗,如果MCU/CPU不在规定的时间内按要求访问看门狗,就认为MCU/CPU处于异常状态,看门狗就会强迫MCU/CPU复位。STC12C5A60S2系列单片机内部也引进了此看门狗功能,使单片机系统可靠性设计变得更加方便/简洁。设时钟为11.0592MHz:看门狗溢出率时间=(12xPre-scalex32768)/11059200下面我们以一个实验来进一步认识STC12C5A60S2的看门狗设置过程,新建工程,编写测试程序main.c#includereg52.hsfrP1M1=0x91;//定义P1口配置寄存器sfrP1M0=0x92;sfrWDT_CONTR=0xc1;//定义看门狗配置寄存器sbitLED1=P1^0;sbitLED2=P1^1;voidDelay_1ms(unsignedintz)//软件延时1ms函数{unsignedintx,y;for(x=z;x0;x--)for(y=1368;y0;y--);//114x12=1368}voidmain(){P1M1&=~(10|11);//配置P1.0P1.1为推挽输出P1M0|=(10|11);LED1=0;//LED1熄灭Delay_1ms(2000);//延时2sWDT_CONTR=0x3a;//启动看门狗for(;;)//LED2隔一秒闪烁{LED2=1;Delay_1ms(1000);LED2=0;Delay_1ms(1000);}}编译、下载目标代码,发现LED1常灭,LED2常亮,这是什么原因呢?STC12C5A60S2不经过配置默认情况下上电复位引脚全部为高电平,LED1复位后被清零,所以复位状态是LED1熄灭,LED2点亮,而后经过2s的延时打开看门狗,看门狗的周期设置为284.4ms,主循环里面LED2间隔1s闪烁,我们在主程序里面并没有喂狗,很显然看门狗会在LED2熄灭之前就复位系统,所以LED2一直是亮的。现在我们修改一下代码,打开定时器0,通过定时器0每隔一段时间去喂狗,粉色字段为新增加代码。#includereg52.hsfrP1M1=0x91;//定义P1口配置寄存器sfrP1M0=0x92;sfrAUXR=0x8e;//定义定时器12分频配置寄存器sfrWDT_CONTR=0xc1;//定义看门狗配置寄存器sbitLED1=P1^0;sbitLED2=P1^1;unsignedintTime=0;voidTimer0_Init(void)//定时器0初始化{AUXR|=(17);//置位T0x12TMOD&=0xf0;TMOD|=0x01;//T0方式2TL0=0x33;//定时4msTH0=0x53;/*注意:0x5333这个值在传统8051下是定时48ms,前面我们已经关闭12分频,所以对于STC12C5A60S2来说是定时4ms*/ET0=1;//允许T0中断TR0=1;//启动定时器}voidDelay_1ms(unsignedintz)//软件延时1ms函数{unsignedintx,y;for(x=z;x0;x--)for(y=1368;y0;y--);//114x12=1368}voidmain(){P1M1&=~(10|11);//配置P1.0P1.1为推挽输出P1M0|=(10|11);LED1=0;//LED1熄灭Delay_1ms(2000);//延时2sTimer0_Init();EA=1;WDT_CONTR=0x3a;//启动看门狗for(;;)//LED2隔一秒闪烁{LED2=1;Delay_1ms(1000);LED2=0;Delay_1ms(1000);}}voidTiemr0_Isr(void)interrupt1{TL0=0x33;//定时器寄存器重装TH0=0x53;Time++;if(Time==50)//定时200ms到这个值要小于看门狗溢出的周期{Time=0;WDT_CONTR=0x3a;//访问看门狗}}编译、下载目标代码,LED2如我们预料