有了一定的基础之后,总感觉亏欠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配置一览表