STC12C5A60S2单片机的总结

STC12C5A60S2单片机的总结

引言:

STC12C5A60S2系列主要性能:

在这里插入图片描述

  • 高速: 1个时钟/机器周期,增型8051内核,速度比普通8051快6~12倍
  • 宽电压: 5.5~4.0V, 2.1~3.6V( STC12LE5A60S2系列)
  • 增加第二复位功能脚/P4.6(高可靠复位, 可调整复位门槛电压,频率<12MHz时,无需此功能)
  • 增加外部掉电检测电路/P4.6,可在掉电时,及时将数据保存进EEPROM,正常工作时
    无需操作EEPROM
  • 低功耗设计:空闲模式(可由任意一个中断唤醒)
  • 低功耗设计:掉电模式(可由外部中断唤醒),可支持下降沿/上升沿和远程唤醒
  • 支持掉电唤醒的管脚: P3.2/INT0, P3.3/INT1, T0/P3.4, T1/P3.5, RxD/P3.0, P1.3/CCP0(或
    P4.2/CCP0), P1.4/CCP1 (或P4.3/CCP1), EX_LVD/P4.6
  • 工作频率: 0~35MHz,相当于普通8051: 0~420MHz
  • 时钟:外部晶体或内部R/C振荡器可选,在ISP下载编程用户程序时设置
  • 8/16/32/40/48/56/60/62K字节片内Flash程序存储器,擦写次数10万次以上
    1280字节片内RAM数据存储器
  • 大容量片内EEPROM功能,擦写次数10万次以上
  • ISP/IAP,在系统可编程/在应用可编程,无需编程器/仿真器
  • 8通道,10位高速ADC,速度可达25万次/秒, 2路PWM还可当2路D/A使用
  • 2通道捕获/比较单元(CCP/PCA/PWM),—也可用来再实现2个定时器或2个外部中断(支持上升沿/下降沿中断)
  • 2个16位定时器(兼容普通8051定时器T0/T1), 2路PCA可再实现2个定时器。可编程时钟输出功能(T0在P3.4输出时钟, T1在P3.5输出时钟,BRT在P1.0输出时钟
  • 硬件看门狗(WDT)
  • 独立波特率发生器
  • SPI高速同步串行通信接口
  • 双串口,全双工异步串行口(UART),兼容普通8051串口,分时复用可当3组使用
  • 先进的指令集结构,兼容普通8051指令集, 有硬件乘法/除法指令
  • 通用I/O口(36/40/44个),复位后为: 准双向口/弱上拉(普通8051传统I/O口)
    可设置成四种模式:准双向口/弱上拉,强推挽/强上拉,仅为输入/高阻,开漏
    每个I/O口驱动能力均可达到20mA,但建议整个芯片不要超过120mA
1.独立串口

STC12C5A60S2系列单片机具有2个采用UART(Universal Asychronous Receiver/Transmitter)工作方式的全双工串行通信接口(串口1和串口2) 。串行口1的两个缓冲器共用的地址码是99H;串行口2的两个缓冲器共用的地址码是9BH。串行口1的两个缓冲器统称串行通信特殊功能寄存器SBUF;串行口2的两个缓冲器统称串行通信特殊功能寄存器S2BUF。

串行口1对应的硬件部分是TxD/P3.1和RxD/P3.0引脚,串行口2 对应的硬件部分是TxD2和RxD2。通过设置特殊功能寄存器AUXR1中的S2_P4/AUXR1.4位,串行口2(UART2)功能可以在P1口和P4口之间任意切换。当串行口2功能在P1口实现时, 对应的管脚是P1.2/RxD2和P1.3/TxD2。当串行口2功能在P4口实现时, 对应的管脚是P4.2/RxD2和P4.3/ TxD2。

1.1 相关寄存器

在这里插入图片描述

SCON寄存器:

在这里插入图片描述

辅助寄存器AUXR:

在这里插入图片描述

独立波特率发生器寄存器BRT(地址为9CH,复位值为00H)用于保存重装时间常数

1.2 实验程序
#include"stc12c5a60s2.h"
typedef unsigned int uint;
typedef unsigned char uchar;

uchar a,flag;

sbit led1=P2^0;

void ck_init()
{
	SCON=0X50;
	BRT=0Xfd;   //一定要11.0592M晶振,BRT的值即为用定时器做波特率发生器方式的定时器匹配值; 9600波特率
	AUXR=0x11;
	ES=1;
	EA=1;
}
void UART_SendData(uchar dat)
{
	SBUF=dat;      
	while(TI==0);  
	TI=0;	
}
void main()
{
	ck_init();
	while(1)
	{
		if(flag==1)
		{
			ES=0;		//关串口中断
			flag=0;
			SBUF=a;
			UART_SendData(a+0x30);
			ES=1;
		}
	}
}

void serial() interrupt 4
{
	flag=1;
	if(SBUF==0x01)
	{
		led1=0;	
	}
	else led1=1;

	a=SBUF;
	RI=0;
}
2.内置看门狗

“看门狗”其实是一个寄存器,每隔一定时间我们需要把寄存器的指定位清零(即所谓的“喂狗”),如果在设置的时间范围内没有“喂狗”,则单片机会自动软复位。“看门狗”的设计是为了防止单片机程序跑飞,确保系统的工作正常。

2.1 看门狗寄存器

在这里插入图片描述
在这里插入图片描述

PS2、PS1、PS0位设置看门狗的超时时间:

在这里插入图片描述

2.2 实验程序:
#include"stc12c5a60s2.h"
typedef unsigned int uint;
typedef unsigned char uchar;

#define wdt_reset_counts 0x3d

sbit p20=P2^0;

void delayms(uint t)
{
	uint x,y;
	for(x=t;x>0;x--)
	for(y=920;y>0;y--);
}
void main()
{
	WDT_CONTR=wdt_reset_counts;
	p20=0;
	delayms(500);
	p20=1;	  
	while(1)
	{
		delayms(5000);   // 延时超过看门狗超时时间单片机会复位,p2.0口led不停闪烁
		WDT_CONTR=wdt_reset_counts;
	}
}
3. EEPROM

STC12C5A60S2系列单片机内部集成了的EEPROM是与程序空间是分开的,利用ISP/IAP技术可将内部Data Flash当EEPROM,擦写次数在10万次以上。EEPROM可分为若干个扇区,每个扇区包含512字节。使用时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同的扇区,不一定要用满。数据存储器的擦除操作是按扇区进行的。

3.1 相关的寄存器

在这里插入图片描述

底层寄存器的操作可以自行看单片机的官方手册,对于使用12单片机的EEPROM,只需要会调用EEPROM模块的API即可。

STC12C5A60S2单片机的EEPROM资源(每个扇区512字节):

在这里插入图片描述

3.2 实验程序
#include"stc12c5a60s2.h"
typedef unsigned int uint;
typedef unsigned char uchar;

#include"lcd.h"

#define	EEP_address	0x0000
uchar code ASCII[] = {'0','1','2','3','4','5','6','7','8','9'};
uchar a,ge,shi;
uchar	TestCnt;

uchar zf[]="num:";
uchar shu;

void	EEPROM_read_n(uint EE_address,uchar *DataAddress,uchar lenth);
void 	EEPROM_SectorErase(uint EE_address);
void 	EEPROM_write_n(uint EE_address,uchar *DataAddress,uchar lenth);

void delayms(uint t)
{
	uint x,y;
	for(x=t;x>0;x--)
	for(y=920;y>0;y--);
}

void main()
{
	LcdInit();
	delayms(5);
	EEPROM_read_n(EEP_address,&TestCnt,1);	//读出保存值   读N个字节函数 最多255字节一次
	TestCnt++;
	if(TestCnt>100) TestCnt=0;  // 如果开机次数大于100,清零
	
	
	EEPROM_SectorErase(EEP_address);  //扇区擦除函数,写入之前必须清楚扇区
	EEPROM_write_n(EEP_address,&TestCnt,1);	//写1个字节函数 最多255字节一次。把开机次数写入EEPROM中
	shi=TestCnt/10;ge=TestCnt%10;

	// 显示开机次数
	LcdWriteCom(0x80);
	for(shu=0;shu<=3;shu++)
	{
		LcdWriteData(zf[shu]);	
	}
	while(1)
	{
		LcdWriteCom(0x05+0x80);LcdWriteData(ASCII[shi]);
		LcdWriteCom(0x06+0x80);LcdWriteData(ASCII[ge]);	
	}
}

完整程序工程的链接:https://pan.baidu.com/s/1feodD7Oa5lkkOm-nmuLnYA?pwd=1234 提取码:1234

4.内置ADC

STC12C5A60AD/S2系列带A/D转换的单片机的A/D转换口在P1口(P1.7-P1.0), 有8路10位高速A/D转换器,速度可达到250KHz(25万次/秒)。

在这里插入图片描述

4.1 相关的寄存器

在这里插入图片描述

内置AD转换的过程总结为4步:1.设置指定的I/O口为模拟输入模式;2.使能;3.设置ADC的通道及转换速度;4.转换结果的处理

1.设置指定的I/O口为模拟输入模式

在这里插入图片描述

2.使能

在这里插入图片描述

3.设置ADC的通道及转换速度

在这里插入图片描述

ADC_START(低3位):1:开始转换;0:转换结束

ADC_FLAG:1:转换结束(需软件清零)

ADC_POWER:ADC电源;1:打开ADC转换的电源,0:关闭ADC转换的电源

4.转换结果的处理:

在这里插入图片描述

常用的方法是设置ADRJ=0,AD转换的结果=ADC_RES的值<<2 | ADC_RESL的值

4.2 实验程序

4.2.1 AD一路非中断方式

/*************	本程序功能说明	**************

P1.0做ADC输入,从串口输出结果(ASCII),9600,8,N,1.

用户只需要更改 MAIN_Fosc 来适应自己的系统。

******************************************/


/*************	用户系统配置	**************/

//#define MAIN_Fosc		22118400L	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ
#define MAIN_Fosc		11095200L	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ

/*************	以下宏定义用户请勿修改	**************/
#include	"reg51.H"
#define	uchar	unsigned char
#define uint	unsigned int
/******************************************/

sfr P1ASF     = 0x9D;	//12C5A60AD/S2系列模拟输入(AD或LVD)选择
sfr ADC_CONTR = 0xBC;	//带AD系列
sfr ADC_RES   = 0xBD;	//带AD系列
sfr ADC_RESL  = 0xBE;	//带AD系列

//								            7       6      5       4         3      2    1    0   Reset Value
//sfr ADC_CONTR = 0xBC;		ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 0000,0000	//AD 转换控制寄存器 
#define ADC_OFF()	ADC_CONTR = 0
#define ADC_ON		(1 << 7)
#define ADC_90T		(3 << 5)
#define ADC_180T	(2 << 5)
#define ADC_360T	(1 << 5)
#define ADC_540T	0
#define ADC_FLAG	(1 << 4)	//软件清0
#define ADC_START	(1 << 3)	//自动清0
#define ADC_CH0		0
#define ADC_CH1		1
#define ADC_CH2		2
#define ADC_CH3		3
#define ADC_CH4		4
#define ADC_CH5		5
#define ADC_CH6		6
#define ADC_CH7		7


/************* 本地变量声明 **************/
sbit	P_TXD1 = P3^1;


/************* 本地函数声明 **************/
void	Tx1Send(uchar dat);
void	PrintString(unsigned char code *puts);
void  	delay_ms(unsigned char ms);
uint	adc10_start(uchar channel);	//channel = 0~7




/********************* 主函数 *************************/
void main(void)
{
	uint	j;

	PrintString("****** STC12C5A60S2系列ADC程序 2011-02-27 ******\r\n");	//上电后串口发送一条提示信息

	P1ASF = (1 << ADC_CH0);			//12C5A60AD/S2系列模拟输入(AD)选择
	ADC_CONTR = ADC_360T | ADC_ON;

	while(1)
	{
		delay_ms(250);
		delay_ms(250);
		delay_ms(250);
		delay_ms(250);
		
		j = adc10_start(0);		// P1.0 ADC
		Tx1Send('A');
		Tx1Send('D');
		Tx1Send('0');
		Tx1Send('=');
		Tx1Send(j/1000 + '0');
		Tx1Send(j%1000/100 + '0');
		Tx1Send(j%100/10 + '0');
		Tx1Send(j%10 + '0');
		Tx1Send(0x0d);
		Tx1Send(0x0a);
		
	}
}

/********************* 做一次ADC转换 *******************/
uint	adc10_start(uchar channel)	//channel = 0~7
{
	uint	adc;
	uchar	i;

	ADC_RES = 0;
	ADC_RESL = 0;

	ADC_CONTR = (ADC_CONTR & 0xe0) | ADC_START | channel; 

//	for(i=0; i<250; i++)		//13T/loop, 40*13=520T=23.5us @ 22.1184M
	i = 250;
	do{
		if(ADC_CONTR & ADC_FLAG)
		{
			ADC_CONTR &= ~ADC_FLAG;
		//	adc = 0;
		//	adc = (ADC_RES << 8) | ADC_RESL;	//ADRJ_enable()   
			//ADC_RES:结果的高8位;ADC_RESL:结果的低2位
			adc = (uint)ADC_RES;
			adc = (adc << 2) | (ADC_RESL & 3);
			return	adc;
		}
	}while(--i);
	return	1024;
}

//========================================================================
// 函数: void  delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2010-12-15
// 备注: 
//========================================================================
void  delay_ms(unsigned char ms)
{
     unsigned int i;
	 do{
	      i = MAIN_Fosc / 14000;
		  while(--i)	;   //14T per loop
     }while(--ms);
}


/********************** 模拟串口相关函数************************/

void	BitTime(void)	//位时间函数
{
	uint i;
	i = ((MAIN_Fosc / 100) * 104) / 140000L - 1;		//根据主时钟来计算位时间
	while(--i);
}

//模拟串口发送
void	Tx1Send(uchar dat)		//9600,N,8,1		发送一个字节
{
	uchar	i;
	EA = 0;
	P_TXD1 = 0;
	BitTime();
	for(i=0; i<8; i++)
	{
		if(dat & 1)		P_TXD1 = 1;
		else			P_TXD1 = 0;
		dat >>= 1;
		BitTime();
	}
	P_TXD1 = 1;
	EA = 1;
	BitTime();
	BitTime();
}

void PrintString(unsigned char code *puts)		//发送一串字符串
{
    for (; *puts != 0;	puts++)  Tx1Send(*puts); 	//遇到停止符0结束
}

4.2.2 AD一路中断方式

/*************	本程序功能说明	**************

P1.0做ADC输入,中断方式读ADC, 从串口输出结果(ASCII),9600,8,N,1.

用户只需要更改 MAIN_Fosc 来适应自己的系统。

******************************************/


/*************	用户系统配置	**************/

//#define MAIN_Fosc		22118400L	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ
#define MAIN_Fosc	   11059200UL	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ

/*************	以下宏定义用户请勿修改	**************/
#include	"reg51.H"
#define	uchar	unsigned char
#define uint	unsigned int
/******************************************/

sfr P1ASF     = 0x9D;	//12C5A60AD/S2系列模拟输入(AD或LVD)选择
sfr ADC_CONTR = 0xBC;	//带AD系列
sfr ADC_RES   = 0xBD;	//带AD系列
sfr ADC_RESL  = 0xBE;	//带AD系列
sbit EADC = IE^5;	//ADC 中断 允许位

//								7       6      5       4         3      2    1    0   Reset Value
//sfr ADC_CONTR = 0xBC;		ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 0000,0000	//AD 转换控制寄存器 
#define ADC_OFF()	ADC_CONTR = 0
#define ADC_ON		(1 << 7)
#define ADC_90T		(3 << 5)
#define ADC_180T	(2 << 5)
#define ADC_360T	(1 << 5)
#define ADC_540T	0
#define ADC_FLAG	(1 << 4)	//软件清0
#define ADC_START	(1 << 3)	//自动清0
#define ADC_CH0		0
#define ADC_CH1		1
#define ADC_CH2		2
#define ADC_CH3		3
#define ADC_CH4		4
#define ADC_CH5		5
#define ADC_CH6		6
#define ADC_CH7		7


/************* 本地变量声明 **************/
sbit	P_TXD1 = P3^1;

unsigned int adc;
bit		B_ADC_OK;



/************* 本地函数声明 **************/
void	Tx1Send(uchar dat);
void	PrintString(unsigned char code *puts);
void  	delay_ms(unsigned char ms);
uint	adc10_start(uchar channel);	//channel = 0~7




/********************* 主函数 *************************/
void main(void)
{
	uint	j;

	PrintString("****** STC12C5A60S2系列ADC程序 2011-02-27 ******\r\n");	//上电后串口发送一条提示信息

	P1ASF = (1 << ADC_CH0);			//12C5A60AD/S2系列模拟输入(AD)选择
	ADC_CONTR = ADC_360T | ADC_ON;
	EADC = 1;	//enable ADC interrupt
	EA   = 1;	//enable all interrupt
	
	while(1)
	{
		delay_ms(250);
		delay_ms(250);
		delay_ms(250);
		delay_ms(250);
		
		ADC_RES  = 0;
		ADC_RESL = 0;
		B_ADC_OK = 0;
		ADC_CONTR = (ADC_CONTR & 0xe0) | ADC_START | ADC_CH0; 
		while(!B_ADC_OK);	//等待ADC完成

		j = adc;
		Tx1Send('A');
		Tx1Send('D');
		Tx1Send('0');
		Tx1Send('=');
		Tx1Send(j/1000 + '0');
		Tx1Send(j%1000/100 + '0');
		Tx1Send(j%100/10 + '0');
		Tx1Send(j%10 + '0');
		Tx1Send(0x0d);
		Tx1Send(0x0a);
		
	}
}

/********************* ADC转换中断 *******************/
void	adc_interrupt(void)	interrupt 5		//channel = 0~7
{
	ADC_CONTR &= ~ADC_FLAG;		//clear ADC flag
	adc = (uint)ADC_RES;
	adc = (adc << 2) | (ADC_RESL & 3);
	B_ADC_OK = 1;		//标志ADC已结束
}

//========================================================================
// 函数: void  delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2010-12-15
// 备注: 
//========================================================================
void  delay_ms(unsigned char ms)
{
     unsigned int i;
	 do{
	      i = MAIN_Fosc / 14000;
		  while(--i)	;   //14T per loop
     }while(--ms);
}


/********************** 模拟串口相关函数************************/

void	BitTime(void)	//位时间函数
{
	uint i;
	i = ((MAIN_Fosc / 100) * 104) / 140000L - 1;		//根据主时钟来计算位时间
	while(--i);
}

//模拟串口发送
void	Tx1Send(uchar dat)		//9600,N,8,1		发送一个字节
{
	uchar	i;

	P_TXD1 = 0;
	BitTime();
	for(i=0; i<8; i++)
	{
		if(dat & 1)		P_TXD1 = 1;
		else			P_TXD1 = 0;
		dat >>= 1;
		BitTime();
	}
	P_TXD1 = 1;
	BitTime();
	BitTime();
}

void PrintString(unsigned char code *puts)		//发送一串字符串
{
    for (; *puts != 0;	puts++)  Tx1Send(*puts); 	//遇到停止符0结束
}

5. PCA定时器做软件定时的功能

STC12C5A60S2系列单片机集成了两路可编程计数器阵列(PCA)模块,可用于软件定时器、外部脉冲的捕捉、高速输出以及脉宽调制(PWM)输出 。

5.1 相关的寄存器

在这里插入图片描述

PCA工作模式寄存器CMOD:

在这里插入图片描述

ECF: PCA计数溢出中断使能位。当ECF = 0时,禁止寄存器CCON中CF位的中断;当ECF = 1时,允许寄存器CCON中CF位的中断。

控制寄存器CCON :

在这里插入图片描述

比较/捕获寄存器CCAPM0和CCAPM1 :

在这里插入图片描述
在这里插入图片描述

PCA的16位计数器 :低8位CL和高8位CH 。CL和CH地址分别为E9H和F9H,复位值均为00H,用于保存PCA的装载值。

PCA捕捉/比较寄存器 — CCAPnL(低位字节)和CCAPnH(高位字节) :

在这里插入图片描述

16位软件定时器模式 :

在这里插入图片描述

5.2 实验程序
#include"stc12c5a60s2.h"	   

typedef unsigned int uint;
typedef unsigned char uchar;

#define fosc 11059200L
#define t100hz (fosc/12/100)		  

sbit p20=P2^0;

uint value;
uchar cnt;

void pcs_ds() interrupt 7
{
	CCF0=0;		//中断标志位清0
	CCAP0L=value;	  //比较寄存器程序赋值(比上次加1倍)
	CCAP0H=value>>8;
	value=value+t100hz;	 //	value一直增加不会溢出??会CL、CH也会溢出。溢出后的数值会丢弃二进制中超过最高位的
	if(cnt--==0)	   //1s  t100hz=0.01s  0.01*100=1s
	{
		cnt=100;
		p20=~p20;
	}
}

void main()
{
	CCON=0;		   //cf cr ccf1 ccf0为0
	CL=0;		//pca计数值初始为0
	CH=0;
	CMOD=0X00;	 //CIDL=0、SYSclk/12、ECF = 0
	value=t100hz;  //0.01s
	CCAP0L=value;	//给比较寄存器赋值
	CCAP0H=value>>8;
	value=value+t100hz;	 //value加一倍
	CCAPM0=0x49;	  //ecmo0 mat0 eccf0为1;ECOM0= 1时,允许比较器功能;匹配将置位CCON寄存;使能CCF0中
	CR=1;  //起动 PCA计数器阵列计数,CCON寄存器的一位
	EA=1;
	cnt=0;
	while(1)
	{
		
	}
}
6. PCA定时器做PWM输出的功能(一路输出)

STC12C5A60S2系列单片机有2路可编程计数器阵列PCA/PWM(通过AUXR1寄存器可以设置PCA/ PWM从P1口切换到P4口)

在这里插入图片描述

6.1 相关寄存器

PCA捕捉/比较寄存器 — CCAPnL(低位字节)和CCAPnH(高位字节) :

在这里插入图片描述

PCA模块PWM寄存器PCA_PWM0和PCA_PWM1 :

在这里插入图片描述

辅助寄存器AUXR1:

在这里插入图片描述

PCA定时器的PWM模式的工作原理:

在这里插入图片描述

当EPCnL = 0及ECCAPnL = 00H时,PWM固定输出高当EPCnL = 1及CCAPnL = 0FFH时,PWM固定输出低 。

6.2 实验程序
#include"stc12c5a60s2.h"

typedef unsigned int uint;
typedef unsigned char uchar;

#define fosc 11059200L

void main()
{
	CCON=0;	   //CF(pca计数溢出标志) CR(是否启动pca计数) CCF1、CCF0(pca模块中断标志)  全清0
	CL=0;  //pca计数值 只有CL计数 8位
	CH=0;  //CH不计数
	CMOD=0X02;	  //选择pca/pwm时钟频率(决定了输出pwm波的频率)  是否中断
	CCAP0H=CCAP0L=0X80;	 //pwm输出通道0(CCP0)   50%占空比  CL与之比较
	CCAPM0=0X42;	 //ecom0 pwm0 置1(使能pwm通道0)

	CCAP1H=CCAP1L=0XFF;	 //pwm输出通道0(CCP1)   0占空比	    CL与之比较
	PCA_PWM1=0X03;		 //固定输出0
	CCAPM1=0X42;	 //ecom1 pwm1 置1(使能pwm通道1)

	CR=1;	//启动pca定时器
	while(1)
	{
		
	}
}
7. PCA定时器做PWM输出的功能(两路输出)

在第6小节的基础上再多定义CCAP1H、CCAPM1寄存器即可实现2路PWM输出

实验程序:

/*************	本程序功能说明	**************

两路PWM测试.

*********************************************/


#include	<reg51.h>
#include<intrins.h>
#define	uchar	unsigned char
#define uint	unsigned int

#define		PCA_IDLE_DISABLE	0		//1: MCU在IDLE模式时禁止PCA工作。	0:  MCU在IDLE模式时允许PCA工作。
#define		PCA_SOURCE_SELECT	4		//选择PCA的基准时钟源。
										//0:系统时钟Fosc/12。
										//1:系统时钟Fosc/2。
										//2:定时器0的溢出。
										//3:ECI/P3.4脚的外部时钟输入(最大=Fosc/2)。
										//4:系统时钟Fosc。
										//5:系统时钟Fosc/4。
										//6:系统时钟Fosc/6。
										//7:系统时钟Fosc/8。

sfr AUXR1 = 0xA2;
sfr	AUXR = 0x8E;
sfr CCON = 0xD8;
sfr CMOD = 0xD9;
sfr CCAPM0 = 0xDA;	//PCA module 0 work mode
sfr CCAPM1 = 0xDB;	//PCA module 1 work mode
sfr CL     = 0xE9;	//PCA counter
sfr CCAP0L = 0xEA;	//PCA模块0的捕捉/比较寄存器低8位。
sfr CCAP1L = 0xEB;	//PCA模块1的捕捉/比较寄存器低8位。
sfr PCA_PWM0 = 0xF2;	//PCA模块0 PWM寄存器。
sfr PCA_PWM1 = 0xF3;	//PCA模块1 PWM寄存器。
sfr CH     = 0xF9;
sfr CCAP0H = 0xFA;		//PCA模块0的捕捉/比较寄存器高8位。
sfr CCAP1H = 0xFB;		//PCA模块1的捕捉/比较寄存器高8位。

sbit CCF0  = CCON^0;	//PCA 模块0中断标志,由硬件置位,必须由软件清0。
sbit CCF1  = CCON^1;	//PCA 模块1中断标志,由硬件置位,必须由软件清0。
sbit CR    = CCON^6;	//1: 允许PCA计数器计数,必须由软件清0。
sbit CF    = CCON^7;	//PCA计数器溢出(CH,CL由FFFFH变为0000H)标志。PCA计数器溢出后由硬件置位,必须由软件清0。

#define		PWM0_NORMAL()	PCA_PWM0 = 0	//PWM0正常输出(默认)
#define		PWM0_OUT_0()	PCA_PWM0 = 3	//PWM0一直输出0
#define		PWM1_NORMAL()	PCA_PWM1 = 0	//PWM1正常输出(默认)
#define		PWM1_OUT_0()	PCA_PWM1 = 3	//PWM1一直输出0


/*************	本地函数声明	**************/

uchar	pwm0,pwm1;

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 108;
	j = 144;
	do
	{
		while (--j);
	} while (--i);
}


void pwm_kz()
{
	if(pwm0>255) pwm0=0;
	if(pwm1>255) pwm1=0;
}

void	main(void)
{
	uint	i;

	//AUXR1 |= (1<<6);	//PCA 从P1口切换到P4.2 P4.3

	pwm0 = 128;			// PWM0 初始值 128
	pwm1 = 64;			// PWM1 初始值 64

	CCAP0H = pwm0;		//改变占空比
	CCAPM0 = 0x42;		//ecom0 pwm0 置1(使能pwm通道0)

	CCAP1H = pwm1;		//改变占空比
	CCAPM1 = 0x42;		//ecom1 pwm1 置1(使能pwm通道1)

	CMOD = (PCA_IDLE_DISABLE << 7) | (PCA_SOURCE_SELECT << 1);	//初始化PCA模式寄存器。
	CL = 0x00;		//pca计数值 只有CL计数 8位
	CH = 0x00;		//CH不计数
	CR = 1;			//启动pca定时器

	while (1)
	{
		for(i=0;i<=255; i++);	//延时一下	255
		{
		 	pwm0++;
			pwm1++;
			pwm_kz();
			CCAP0H = pwm0;		//set PWM wide
			CCAP1H = pwm1;		//set PWM wide
			Delay10ms();
		}		
	}
}

8. PCA定时器用于扩展外部中断

主要的寄存器:PCA比较/捕获寄存器CCAPM0和CCAPM1 :
在这里插入图片描述

设置好CAPN0、ECCF0位

实验程序:

#include"stc12c5a60s2.h"
typedef unsigned int uint;
typedef unsigned char uchar;

sbit p10=P1^0;

void pca_bh() interrupt 7
{
	if(CCF0==1)
	{
		CCF0=0;
		p10=~p10;
	}
}

void main()
{
	CCON=0;	  			//CF(pca计数溢出标志) CR(是否启动pca计数) CCF1、CCF0(pca模块中断标志)  全清0
	CL=CH=0;  			//pca计数值
	CMOD=0X00; 			//选择pca/pwm时钟频率(决定了输出pwm波的频率)  是否中断
	CCAPM0=0X11;	 //下降沿捕获
	//CCAPM0=0X21;	 //上升沿捕获
	//CCAPM0=0X21;	 //下降、上升都捕获
	CR=1;	  //启动pca定时器
	EA=1;	  //开启总中断
	while(1)
	{
		
	}
}
9. PCA定时器用于输入捕获

工作原理:

在这里插入图片描述

实验程序:

/*************	本程序功能说明	**************

STC12C5A60S2系列 从P1.3 P1.4 做捕捉输入,从串口输出结果(ASCII),9600,8,N,1.
STC12C5204AD系列 从P3.7 P3.5 做捕捉输入,从串口输出结果(ASCII),9600,8,N,1.

******************************************/


/*************	用户系统配置	**************/

//#define MAIN_Fosc		22118400L	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ
#define MAIN_Fosc		11059200L	//定义主时钟, 模拟串口和和延时会自动适应。5~35MHZ

#define		PCA_IDLE_DISABLE	0			//1: MCU在IDLE模式时禁止PCA工作。	0:  MCU在IDLE模式时允许PCA工作。
#define		PCA_SOURCE_SELECT	0			//选择PCA的基准时钟源。
											//0:系统时钟Fosc/12。
											//1:系统时钟Fosc/2。
											//2:定时器0的溢出。
											//3:ECI/P3.4脚的外部时钟输入(最大=Fosc/2)。
											//4:系统时钟Fosc。
											//5:系统时钟Fosc/4。
											//6:系统时钟Fosc/6。
											//7:系统时钟Fosc/8。
#define		PCA_ECF				1		//1: 允许PCA计数器溢出中断,0: 禁止


/*************	以下宏定义用户请勿修改	**************/
#include	"reg51.H"
#define	uchar	unsigned char
#define uint	unsigned int
/******************************************/

sfr CCON = 0xD8;	//STC12C5A60S2系列
sfr CMOD = 0xD9;	//STC12C5A60S2系列
sfr CCAPM0 = 0xDA;	//PCA模块0的工作模式寄存器。
sfr CCAPM1 = 0xDB;	//PCA模块1的工作模式寄存器。

sfr CL     = 0xE9;	//
sfr CCAP0L = 0xEA;	//PCA模块0的捕捉/比较寄存器低8位。
sfr CCAP1L = 0xEB;	//PCA模块1的捕捉/比较寄存器低8位。

sfr PCA_PWM0 = 0xF2;	//PCA模块0 PWM寄存器。
sfr PCA_PWM1 = 0xF3;	//PCA模块1 PWM寄存器。
sfr CH     = 0xF9;
sfr CCAP0H = 0xFA;		//PCA模块0的捕捉/比较寄存器高8位。
sfr CCAP1H = 0xFB;		//PCA模块1的捕捉/比较寄存器高8位。

sbit CCF0  = CCON^0;	//PCA 模块0中断标志,由硬件置位,必须由软件清0。
sbit CCF1  = CCON^1;	//PCA 模块1中断标志,由硬件置位,必须由软件清0。
sbit CR    = CCON^6;	//1: 允许PCA计数器计数,必须由软件清0。
sbit CF    = CCON^7;	//PCA计数器溢出(CH,CL由FFFFH变为0000H)标志。PCA计数器溢出后由硬件置位,必须由软件清0。

/************* 本地变量声明 **************/
uint	CCAP0_tmp,CCAP1_tmp;
uint	CCAP0_Last,CCAP1_Last;
bit		B_Cap0,B_Cap1;
sbit	P_TXD1 = P3^1;

sbit	P10 = P1^0;

/************* 本地函数声明 **************/
void	Tx1Send(uchar dat);
void	PrintString(unsigned char code *puts);


void tx(uchar id,uint dat)
{
	Tx1Send('P');
	Tx1Send('C');
	Tx1Send('A');
	Tx1Send(id + '0');
	Tx1Send('=');
	Tx1Send(dat/10000 + '0');
	Tx1Send(dat%10000/1000 + '0');
	Tx1Send(dat%1000/100 + '0');
	Tx1Send(dat%100/10 + '0');
	Tx1Send(dat%10 + '0');
	Tx1Send(0x0d);
	Tx1Send(0x0a);
}



/********************* 主函数 *************************/
void main(void)
{
	CCAPM0 = 0x11;	//CCAP0下降沿捕捉,允许中断		下降沿捕捉: 0x11,  上升沿捕捉: 0x21, 上升下降沿捕捉: 0x31
	CCAPM1 = 0x11;	//CCAP1下降沿捕捉,允许中断		下降沿捕捉: 0x11,  上升沿捕捉: 0x21, 上升下降沿捕捉: 0x31
	CMOD = (PCA_IDLE_DISABLE << 7) | (PCA_SOURCE_SELECT << 1) | PCA_ECF;	//初始化PCA模式寄存器。
	CL = 0;					//清空PCA基本计数器。
	CH = 0;
	CR = 1;					//Start CR
	EA = 1;

	PrintString("****** STC12C5A60S2系列MCU捕捉程序 2011-02-25 ******\r\n");	//上电后串口发送一条提示信息

	while(1)	 
	{
		if(B_Cap0)
		{
			B_Cap0 = 0;
			tx(0, CCAP0_tmp - CCAP0_Last);
			CCAP0_Last = CCAP0_tmp;	  //为什么要减去上次值,CL和CH没有清零
		}
		if(B_Cap1)
		{
			B_Cap1 = 0;
			tx(1, CCAP1_tmp - CCAP1_Last);
			CCAP1_Last = CCAP1_tmp;
		}
	}
}



//========================================================================
// 函数: void PCA_interrupt (void) interrupt 7
// 描述: PCA中断服务程序。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2009-12-30
// 备注: 
//========================================================================
void PCA_interrupt (void) interrupt 7
{
	if(CCF0 == 1)		//PCA模块0中断
	{
		CCF0 = 0;		//清PCA模块0中断标志
		CCAP0_tmp = CCAP0H;	//读CCAP0H (CH CL值会自动装载到CCAP0H  CCAP0L)
		CCAP0_tmp = (CCAP0_tmp << 8) + CCAP0L;
		B_Cap0 = 1;
	}

	if(CCF1 == 1)	//PCA模块1中断
	{
		CCF1 = 0;		//清PCA模块1中断标志
		CCAP1_tmp = CCAP1H;	//读CCAP0H
		CCAP1_tmp = (CCAP1_tmp << 8) + CCAP1L;
		B_Cap1 = 1;
	}

	if(CF == 1)	//PCA溢出中断
	{
		CF = 0;			//清PCA溢出中断标志
		P10 = ~P10;		//14HZ at 22.1184MHZ
	}
}

/********************** 模拟串口相关函数************************/

void	BitTime(void)	//位时间函数
{
	uint i;
	i = ((MAIN_Fosc / 100) * 104) / 140000L - 1;		//根据主时钟来计算位时间
	while(--i);
}

//模拟串口发送
void	Tx1Send(uchar dat)		//9600,N,8,1		发送一个字节
{
	uchar	i;
	P_TXD1 = 0;
	BitTime();
	for(i=0; i<8; i++)
	{
		if(dat & 1)		P_TXD1 = 1;
		else			P_TXD1 = 0;
		dat >>= 1;
		BitTime();
	}
	P_TXD1 = 1;
	BitTime();
	BitTime();
}

void PrintString(unsigned char code *puts)		//发送一串字符串
{
    for (; *puts != 0;	puts++)  Tx1Send(*puts); 	//遇到停止符0结束
}

10. PCA定时器用于生成高速脉冲

工作原理:

在这里插入图片描述

实验程序:

/*************	本程序功能说明	**************

PCA中断测试程序.
PCA计数器溢出中断,从P1.0输出一个方波(168.75HZ at 22.1184MHZ).
CCAP0模块中断,重装比较值,输出方波(1KHZ  at 22.1184MHZ).
CCAP1模块中断,重装比较值,输出方波(2KHZ  at 22.1184MHZ).


******************************************/

#include	"PCA.h"


sbit	P10 = P1^0;
sbit	P11 = P1^1;

unsigned int CCAP0_tmp,CCAP1_tmp;

void	PWMn_init(void);


/******************** 主函数 **************************/
//========================================================================
// 函数: void main(void)
// 描述: 空函数。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2009-12-30
// 备注: 
//========================================================================
void main(void)
{
	PWMn_init();	//初始化PCA
	
	while(1)
	{
	
	}

}


//========================================================================
// 函数: void	PWMn_init(void)
// 描述: 初始化程序。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2009-12-30
// 备注: 
//========================================================================
void	PWMn_init(void)
{
	#ifdef	STC12C5201AD
		P3M1 &= ~0xA0,	P3M0 |=  0xA0;		//CCAP0、CCAP1使用PUSH-PULL输出模式,STC12C5201AD系列。
	#else
		P1M1 &= ~0x18,	P1M0 |=  0x18;		//CCAP0、CCAP1使用PUSH-PULL输出模式,STC12C5A60S2系列。
	#endif
	CCON = 0;					//清除CF、CR、CCF0、CCF1
	IPH |= 0x80;				//PCA中断使用最高优先级
	PPCA = 1;
	CMOD = (PCA_IDLE_DISABLE << 7) | (PCA_SOURCE_SELECT << 1) | PCA_ECF;	//初始化PCA模式寄存器。(决定高速脉冲频率)
	CCAPM0 = 0x4D;				//高速输出模式,允许比较匹配中断(ECCF0=1)。
	CCAPM1 = 0x4D;				//高速输出模式,允许比较匹配中断(ECCF1=1)。
	CL = 0;						//清空PCA基本计数器。
	CH = 0;
	CCAP0_tmp = 0;				//清空CCAP0重装载影射寄存器。
	CCAP1_tmp = 0;				//清空CCAP0重装载影射寄存器。
	EA = 1;						//允许总中断
	CR = 1;						//启动PCA。
}

//========================================================================
// 函数: void PCA_interrupt (void) interrupt 7
// 描述: PCA中断服务程序。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2009-12-30
// 备注: 
//========================================================================
void PCA_interrupt (void) interrupt 7
{
	if(CCF0 == 1)		//PCA模块0中断
	{
		CCF0 = 0;		//清PCA模块0中断标志
		CCAP0_tmp +=2765 ;		//1KHZ  at   11.0592M  2765		
		CCAP0L = CCAP0_tmp%256;			//将影射寄存器写入捕获寄存器,先写CCAP0L   (自己改的是对的!!!!!)
		CCAP0H = CCAP0_tmp/256;	//后写CCAP0H
	}

	if(CCF1 == 1)	//PCA模块1中断
	{
		CCF1 = 0;		//清PCA模块1中断标志
		CCAP1_tmp +=28;		//2KHZ at 22.1184MHZ 5530			  11.0592M   28	    (这里例程是错的!!,自己计算的28)
		CCAP1L = (unsigned char)CCAP1_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
		CCAP1H = (unsigned char)(CCAP1_tmp >> 8);	//后写CCAP0H
	}
	if(CF == 1)	//PCA溢出中断
	{
		CF = 0;			//清PCA溢出中断标志
		P10 = ~P10;		//168.75HZ at 22.1184MHZ
	}
}

该程序完整工程文件链接:https://pan.baidu.com/s/1jNUyDsEftqcvIGZobNIHfA?pwd=1234
提取码:1234

  • 29
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STC12C5A60S2单片机手册是一本详细介绍STC12C5A60S2单片机特性、功能以及使用方法的参考资料。这本手册对于想要了解和使用STC12C5A60S2单片机的工程师和学生来说非常重要。 首先,手册会详细介绍STC12C5A60S2单片机的基本特性。它将包括单片机的工作电压范围、时钟频率、存储容量等信息,这些特性对于确保单片机能够适用于特定的应用场景非常关键。 其次,手册会提供STC12C5A60S2单片机的功能描述。这包括单片机所支持的指令集、输入输出端口、通信接口等。这些功能可以帮助工程师更好地了解单片机的能力,为他们设计和开发适当的电路布局和软件代码提供指导。 在手册中,还会给出STC12C5A60S2单片机的引脚功能描述和电气特性。这将涵盖每个引脚的具体功能和用途,以及引脚的电气特性,例如驱动能力和输入电平范围。工程师可以根据这些信息来设计适当的电路连接。 此外,手册还会提供关于STC12C5A60S2单片机编程和调试的详细信息。它包括单片机所支持的编程语言、开发环境以及调试工具。这对于学习和使用STC12C5A60S2单片机来说非常重要,有助于确保开发过程的顺利进行。 最后,手册还会提供示例电路图和代码,以帮助工程师更好地理解和应用STC12C5A60S2单片机。这些示例可以作为起点,为工程师提供一些实际应用的指导,帮助他们更好地利用单片机的功能。 总的来说,STC12C5A60S2单片机手册是一本功能丰富的参考资料,它提供了关于STC12C5A60S2单片机基本特性、功能描述、引脚功能和电气特性、编程和调试等方面的详细信息。这本手册对于学习和使用STC12C5A60S2单片机的人来说是一个宝贵的工具,将帮助他们更好地理解和应用这款单片机

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值