STC12手册通读

本文详细介绍了51单片机的相关知识点,包括串口下载程序ISP、波特率发生器、时钟输出、IAP/ISP理解、FLASH程序存储区、工作模式、IO口特性、寻址方式、中断优先级嵌套、UART寄存器、ADC使用等,并提供了多个实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有了一定的基础之后,总感觉亏欠51点什么。有时候做起东西来也并不是那么的得心应手,特别对于51单片机的寄存器。

今天特地重新翻阅了一遍51的手册,很多东西自己真的没注意到,特地记录。

1.关于串口下载程序ISP

犹记得学习51那会,有次因为下载程序怎么也下载不进去。就跑到交流群里面,问老宋。 老宋告诉我把P10和P11和GND短接起来再下载,然后断开再下载试试。。当时也不明白缘由,今日翻阅手册恍然大悟。 我们是可以通过P10/P11禁止ISP下载程序的!

这里写图片描述

2、关于波特率发生器

89系列的单片机是没有独立的波特率发生器这一说的,但是要注意。89系列的波特率发生器只能让T1或者T2来做,(通常T2的配置较为繁琐,故一般用的都是T1)。然后到了STC12就有了自己的独立波特率发生器BRT。同时还需要注意的是,12单片机没了T2这个定时器!

3、关于时钟输出

12单片机有3种时钟输出方式:
T0 (P34)、T1(P35)以及利用有源晶振接入XTAL1,然后在XTAL2得到输出的脉冲(需要串接一个200欧的电阻)。
这里就提到了12单片机外接有源晶振的情况,要特别注意XTAL2引脚是悬空的。这里写图片描述

对了,还有个时钟输出的三个寄存器。
这里写图片描述

要特别注意配置的三个地方:
这里写图片描述
① 时钟输出只能工作在8位自动重装载模式下
② 溢出率其实就是多少个数溢出一次,所以直接就是SYSCLK/(256-TH1)对应的就是溢出率
③C/T的选择,0一个是内部时钟时钟计数,1是外部输入时钟计数。

eg1: 独立波特率发生器用来时钟输出

#include <stc12.h>

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L
//#define MODE1T                      //Timer clock mode, comment this line is 12T mode, uncomment is 1T mode

#ifdef MODE1T
#define F38_4KHz (256-FOSC/2/38400)    //38.4KHz frequency calculation method of 1T mode
#else
#define F38_4KHz (256-FOSC/2/12/38400) //38.4KHz frequency calculation method of 12T mode
#endif

sbit BRTCLKO  = P1^0;               //BRT clock output pin

//-----------------------------------------------

/* main program */
void main()
{
#ifdef MODE1T
    AUXR = 0x04;                    //BRT work in 1T mode
#endif
    BRT = F38_4KHz;                 //initial BRT
    AUXR |= 0x10;                   //BRT start running
    WAKE_CLKO = 0x04;               //enable BRT clock output

    while (1);                      //loop
}

eg2: T0用来时钟输出 (必须工作在8位自动重装载模式下)

#include <stc12.h>

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L
//#define MODE1T                      //Timer clock mode, comment this line is 12T mode, uncomment is 1T mode

#ifdef MODE1T
#define F38_4KHz (256-FOSC/2/38400)    //38.4KHz frequency calculation method of 1T mode
#else
#define F38_4KHz (256-FOSC/2/12/38400) //38.4KHz frequency calculation method of 12T mode
#endif

sbit T0CLKO  = P1^0;               //T0 clock output pin

//-----------------------------------------------

/* main program */
void main()
{
#ifdef MODE1T
    AUXR = 0x80;                    //T0 work in 1T mode
#endif
    TMOD = 0x02;                    //T0 T1 必须8位自动重装载
    TH0 = F38_4KHz;                 //initial TH0
    TL0 = F38_KHz;
    TR0 = 1;                        //T0 start running
    WAKE_CLKO = 0x01;               //enable T0 clock output

    while (1);                      //loop
}

eg3: 同T0 此处省略。。。

#include <stc12.h>

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L
//#define MODE1T                      //Timer clock mode, comment this line is 12T mode, uncomment is 1T mode

#ifdef MODE1T
#define F18_4KHz (256-FOSC/2/18400)    //18.4K
#define F28_4KHz (256-FOSC/2/28400)    //28.4K
//#define F38_4KHz (256-FOSC/2/38400)    //38.4KHz frequency calculation method of 1T mode

#else
#define F18_4KHz (256-FOSC/2/12/18400) //18.4K
#define F28_4KHz (256-FOSC/2/12/28400) //28.4K
#define F38_4KHz (256-FOSC/2/12/38400) //38.4KHz frequency calculation method of 12T mode
#endif

//sbit T0CLKO  = P3^4;               //T0 clock output pin
//sbit T1CLKO  = P3^5;               //T1 clock output pin
//sbit BRTCLKO  = P1^0;               //BRT clock output pin
//-----------------------------------------------

/* main program */
void main()
{
#ifdef MODE1T
    AUXR = 0x80;                    //T0 work in 1T mode
#endif
    TMOD = 0x22;                    //T0 T1
    BRT = F18_4KHz;
    TH0 = F28_4KHz;                 //initial TH0
    TL0 = T28_4KHz;
    TH1 = F38_4KHz;
    TL1 = F18_4KHz;

    AUXR |= 0x10;
    TR0 = 1;                        //T0 start running
    TR1 = 1;

    WAKE_CLKO = 0x04;
    WAKE_CLKO |= 0x01;               //enable T0 clock output
    WAKE_CLKO |= 0x02;

    while (1);                      //loop
}

4、IAP/ISP的理解

ISP其实就可简单理解为下载程序的那个STC-ISP下载器,在系统编程。
当然也有个ISP系统监控程序区。可参考:STC12复位到ISP自动下载程序

AP开头的单片机在程序运行过程中由程序修改或者擦除整个Flash、

5、FLASH 程序存储区
程序存储区,让传统的只读程序存储器变成可读/写程序存储器,程序运行过程中写入flash的数据和程序一样,具有掉电不丢失的功能。

6、单片机的三种工作模式
三种工作方式: 空闲工作模式,正常工作模式,以及掉电模式
特别注意一下,空闲模式

以前用PCA的时候,没有特意去看,其实这玩意可没那么肤浅。。。

手册上写的也是很清楚的,空闲工作模式下CPU无时钟停止工作,其余模块仍然继续工作,看门狗是否工作要看它的相关寄存器配置。任何一个中断都可以唤醒空闲模式为正常工作。

7、关于IO口
四种工作方式:

准双向/弱上拉、强推挽/强上拉、高阻态/仅为输入、开漏/外加上拉电阻可作为输入

准双向IO口,要正确读取外部状态,必须先保证自己是高电平。
这里写图片描述

IO口使用的注意事项:
值得注意的就是12有别于89的速度问题。
这里写图片描述

让IO口上电复位是低电平的硬件实现
这里写图片描述

8、关于指令集的寻址方式:

立即寻址
直接寻址
间接寻址
寄存器寻址
相对寻址
变址寻址
位寻址

9、关于中断优先级的嵌套问题

传统的8051单片机对中断优先级的设定只要一个寄存器就是IP,故最多可以形成两层嵌套,第一级和最后一级。

12多加了IPH,故可以形成4层嵌套。
这里写图片描述

这里写图片描述

10、关于STC-ISP中的串口初始化函数直接可调用的!

void UartInit(void)     //9600bps@11.0592MHz
{
    AUXR &= 0xF7;       //波特率不倍速
    S2CON = 0x50;       //8位数据,可变波特率
    AUXR |= 0x04;       //独立波特率发生器时钟为Fosc,即1T
    BRT = 0xDC;     //设定独立波特率发生器重装值
    AUXR |= 0x10;       //启动独立波特率发生器
}
void UartInit(void)     //9600bps@11.0592MHz
{
    AUXR &= 0xF7;       //波特率不倍速
    S2CON = 0x50;       //8位数据,可变波特率
    AUXR &= 0xFB;       //独立波特率发生器时钟为Fosc/12,即12T
    BRT = 0xFD;     //设定独立波特率发生器重装值
    AUXR |= 0x10;       //启动独立波特率发生器
}

11、关于C/T
C/T = 0 就是对内部时钟进行计数

C/T = 1 就是对外部脉冲进行计数

12、UART 的寄存器组成
这里写图片描述

13、12的ADC使用

寄存器组成
这里写图片描述

结果寄存器
这里写图片描述

12具有8路10位ADC 就是在P1口的八个

ADRJ = 0
这里写图片描述
ADRJ = 1
这里写图片描述

P1ASF直接控制是否作为模拟功能口使用—相当于IO口和AD口开关选择
这里写图片描述

而CHX 是决定打开哪个AD开关作为模拟输入
这里写图片描述

13、PCA
突然意识到一点,ECF和ECCF0是不一样的,也没有什么“牵制”的关系。
ECF是计数器溢出的中断标志。
而ECCF是发生匹配或者捕获的中断标志!
①、定时器
步长的计算是这样的:步长 = 定时时间 * 计数脉冲频率

#include "reg51.h"
#include "intrins.h"

#define FOSC    11059200L
#define T100Hz  (FOSC / 12 / 100)   //频率设定

typedef unsigned char BYTE;
typedef unsigned int WORD;

sbit PCA_LED    =   P1^1;           //PCA test LED

BYTE cnt;
WORD value;

void PCA_isr() interrupt 7 using 1
{
    CCF0 = 0;                       //Clear interrupt flag
    CCAP0L = value;
    CCAP0H = value >> 8;            //Update compare value
    value += T100Hz;
    if (cnt-- == 0)
    {
        cnt = 100;                  //Count 100 times
        PCA_LED = !PCA_LED;         //Flash once per second
    }
}

void main()
{
    CCON = 0;                       //Initial PCA control register
                                    //PCA timer stop running
                                    //Clear CF flag
                                    //Clear all module interrupt flag
    CL = 0;                         //Reset PCA base timer
    CH = 0;
    CMOD = 0x00;                    //Set PCA timer clock source as Fosc/12
                                    //Disable PCA timer overflow interrupt
    value = T100Hz;
    CCAP0L = value;
    CCAP0H = value >> 8;            //Initial PCA module-0
    value += T100Hz;
    CCAPM0 = 0x49;                  //PCA module-0 work in 16-bit timer mode and enable PCA interrupt

    CR = 1;                         //PCA timer start run
    EA = 1;
    cnt = 0;

    while (1);
}

②外部中断
设置好哪个沿触发就好

#include "reg51.h"
#include "intrins.h"

typedef unsigned char BYTE;
typedef unsigned int WORD;
sbit PCA_LED    =   P1^0;           //PCA test LED

void PCA_isr() interrupt 7 using 1
{
    CCF0 = 0;                       //Clear interrupt flag
    PCA_LED = !PCA_LED;             //toggle the test pin while CEX0(P1.3) have a falling edge
}

void main()
{
    CCON = 0;                       //Initial PCA control register
                                    //PCA timer stop running
                                    //Clear CF flag
                                    //Clear all module interrupt flag
    CL = 0;                         //Reset PCA base timer
    CH = 0;
    CMOD = 0x00;                    //Set PCA timer clock source as Fosc/12
                                    //Disable PCA timer overflow interrupt
                                    //触发方式选择
    CCAPM0 = 0x11;                  //PCA module-0 capture by a negative tigger on CEX0(P1.3) and enable PCA interrupt
//  CCAPM0 = 0x21;                  //PCA module-0 capture by a rising edge on CEX0(P1.3) and enable PCA interrupt
//  CCAPM0 = 0x31;                  //PCA module-0 capture by a transition (falling/rising edge) on CEX0(P1.3) and enable PCA interrupt

    CR = 1;                         //PCA timer start run
    EA = 1;

    while (1);
}

③PWM

频率各个通道都是一样的,唯一可调就是通过CCAPnH的占空比

PWM默认输出频率 = 系统时钟/12/256
PWM输出占空比 = (1-CCAPnH/256)
CCAPnH = (1-占空比)*256

void PwnInit()
{
    //PWM1
    CCON=0x00;//PCA初始化
    CL=0;//PCA的16位计数器低八位
    CH=0;//PCA的16位计数器高八位
    CMOD=0x00;//选择 系统时钟/12 为计数脉冲,则PWM的频率f=sysclk/256/12;

    CCAP0H=0x80;//占空比控制50%
    CCAP0L=0x80;  
    PCA_PWM0=0x00;//控制占空比的第九位为0

    //P13作为PWM0输出
    CCAPM0=0x42; //允许
    //CCAPM0=0x40; //禁止

    //PWM2  
    CCAP1H=0x80;//占空比控制
    CCAP1L=0x80;  
    PCA_PWM1=0x00;//控制占空比的第九位为0

    //P14作为PWM1输出
    CCAPM1=0x42;//允许
    //CCAPM1=0X40;//禁止

    CR=1;//启动PCA计数器
}

④高速脉冲输出模式
PCA计数器步长值 = 计数脉冲频率/(2*Fout)


#include "reg51.h"
#include "intrins.h"

#define FOSC    11059200L
#define T100KHz ((FOSC / 2)/ 2 / 100000)

typedef unsigned char BYTE;
typedef unsigned int WORD;
sbit PCA_LED    =   P1^0;           //PCA test LED

BYTE cnt;
WORD value;

void PCA_isr() interrupt 7 using 1
{
    CCF0 = 0;                       //Clear interrupt flag
    CCAP0L = value;
    CCAP0H = value >> 8;            //Update compare value
    value += T100KHz;
}

void main()
{
    CCON = 0;                       //Initial PCA control register
                                    //PCA timer stop running
                                    //Clear CF flag
                                    //Clear all module interrupt flag
    CL = 0;                         //Reset PCA base timer
    CH = 0;
    CMOD = 0x02;                    //Set PCA timer clock source as Fosc/2
                                    //Disable PCA timer overflow interrupt
    value = T100KHz;
    CCAP0L = value;                 //P1.3 output 100KHz square wave
    CCAP0H = value >> 8;            //Initial PCA module-0
    value += T100KHz;
    CCAPM0 = 0x4d;                  //PCA module-0 work in 16-bit timer mode and enable PCA interrupt, toggle the output pin CEX0(P1.3)

    CR = 1;                         //PCA timer start run
    EA = 1;
    cnt = 0;

    while (1);
}

14、硬件SPI的实验

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

①关于单主单从
这里写图片描述

②关于互为主从
这里写图片描述

这里写图片描述

SS被忽略的情况
这里写图片描述

③一主多从
这里写图片描述

SPI配置一览表
这里写图片描述

``` #include <STC15F2K60S2.H> #include <IIC.H> #include <key.H> #include <smg.H> #include <led.H> #include <shaosheng.H> #include <onewire.H> #include <chuanko.H> #include <init.H> #include <DS1302.H> #include "stdio.h" #include "intrins.h" #define SCK P35 #define MISO P36 float t[29]; unsigned char i=1; unsigned int ma[40]; float ma2[20]; unsigned char l; unsigned char n=1; unsigned int a=20,shang,xia; unsigned int upper=10; unsigned int lower=10; unsigned int jiesho[30]={20,20,20,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30}; float max, min; unsigned char q; void find_max_min(float arr[], int siz, int* max, int* min) ; void Delay500ms(void) { unsigned char data i, j, k; _nop_(); _nop_(); i = 23; j = 205; k = 120; do { do { while (--k); } while (--j); } while (--i); } // SPI ????,??24?CS?? unsigned int SPI_Read(unsigned char csIndex) { unsigned int dat = 0; unsigned char i; // ?????SPI?? switch(csIndex) { case 0: CS0 = 0; break; case 1: CS1 = 0; break; case 2: CS2 = 0; break; case 3: CS3 = 0; break; case 4: CS4 = 0; break; case 5: CS5 = 0; break; case 6: CS6 = 0; break; case 7: CS7 = 0; break; case 8: CS8 = 0; break; case 9: CS9 = 0; break; case 10: CS10 = 0; break; case 11: CS11 = 0; break; case 12: CS12 = 0; break; case 13: CS13 = 0; break; case 14: CS14 = 0; break; case 15: CS15 = 0; break; case 16: CS16 = 0; break; case 17: CS17 = 0; break; case 18: CS18 = 0; break; case 19: CS19 = 0; break; case 20: CS20 = 0; break; case 21: CS21 = 0; break; case 22: CS22 = 0; break; case 23: CS23 = 0; break; default: break; } // ??16??? for (i = 0; i < 16; i++) { SCK = 1; // ????? dat <<= 1; if (MISO == 1) { dat |= 0x01; // ???? } SCK = 0; // ????? } // ?????SPI?? switch(csIndex) { case 0: CS0 = 1; break; case 1: CS1 = 1; break; case 2: CS2 = 1; break; case 3: CS3 = 1; break; case 4: CS4 = 1; break; case 5: CS5 = 1; break; case 6: CS6 = 1; break; case 7: CS7 = 1; break; case 8: CS8 = 1; break; case 9: CS9 = 1; break; case 10: CS10 = 1; break; case 11: CS11 = 1; break; case 12: CS12 = 1; break; case 13: CS13 = 1; break; case 14: CS14 = 1; break; case 15: CS15 = 1; break; case 16: CS16 = 1; break; case 17: CS17 = 1; break; case 18: CS18 = 1; break; case 19: CS19 = 1; break; case 20: CS20 = 1; break; case 21: CS21 = 1; break; case 22: CS22 = 1; break; case 23: CS23 = 1; break; default: break; } // ??????????? if (dat == 0) { return 0; // ?????0,?????????? } return dat; // ?????16??? } // ?????? float Get_Temperature(unsigned char ma) { unsigned int dat = 0; unsigned int sum = 0; unsigned char i; // ????????? for (i = 0; i < 10; i++) { dat = SPI_Read(ma); // ?????????????SPI?? if (dat >4000) { return 0; // ???????0,??0.0???????? } dat >>= 3; // ???? sum += dat; } dat = sum / 10; // ????? return (float)(dat * 0.25); // ?????? } void Timer0_Init(void) //10??@12.000MHz { AUXR &= 0x7F; //?????12T?? TMOD &= 0xF0; //??????? TL0 = 0x60; //??????? TH0 = 0x1f; //??????? TF0 = 0; //??TF0?? TR0 = 1; //???0???? ET0=1; EA=1; }```分析下
03-08
//头文件 #include <STC15F2K60S2.H> #include "seg1.h" #include "key1.h" #define uchar unsigned char #define uint unsigned int #include <intrins.h> //变量声明 uchar key_slow;//10ms uint seg_slow;//500ms uchar seg_pos; uchar seg_buf[8]={10}; uchar key_val,key_up,key_down,key_old; uchar timer_400ms; bit seg_flas; uchar interval = 400; uchar led_mode; uchar ucled; uchar led_buf[]={0x7e,0xbd,0xdb,0xe7}; uchar led_index; uint sys_tick; uint led_time[]={400,400,400,400}; //按键处理函数 void key_proc() { if(key_slow) return; key_slow = 1; /*switch(key_down) case 1: break; case 2: break; case 3: break; case 4: break;*/ } //信息处理函数 void seg_proc() { if(seg_slow) return; seg_slow = 1; key_val = key_read(); key_up = ~key_val&(key_val^key_old); key_down = key_val&(key_val^key_old); key_old = key_val; } //其他处理函数 void led_proc() { P2 = P2&0X1F|0X80; P0 = ucled; if(sys_tick == led_time[led_mode]) { switch(led_mode){ case 0: ucled = 0xfe; ucled = _crol_(ucled,1); if(ucled == 0x7f) led_mode = 2; break; case 1: ucled = _cror_(ucled,1); if(ucled == 0xfe) led_mode = 3; break; case 2: ucled = led_buf[led_index]; if(++led_index == 4) { led_mode = 3; led_index = 3; } break; case 3: ucled = led_buf[led_index]; if(--led_index == 255) { led_mode = 0; led_index = 0; } break; } } } //定时器0初始化函数 void Timer0Init(void) //1毫秒@11.0592MHz { AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0x66; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; EA = 1; } //定时器0中断服务函数 void timer0_server() interrupt 1 { TL0 = 0x66; TH0 = 0xFC; // if(++seg_pos == 8) seg_pos = 0; // seg_disp(seg_pos,seg_buf[seg_pos]); if(++key_slow == 10) key_slow = 0; if(++seg_slow == 500) seg_slow = 0; sys_tick++; } //主函数 void main() { Timer0Init(); while(1) { key_proc(); seg_proc(); led_proc(); } }分析led_proc()代码中的问题
03-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReCclay

如果觉得不错,不妨请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值