STC單片機有89、90、10、11、12、15這幾個大系列,每個系列都有自己的特點。89系列是老舊而傳統(tǒng)的單片機,可以和AT89系列完全兼容,是12T單片機。90是基于89系列的改進型產(chǎn)品系列。10和11系列是有著便宜價格的1T單片機,有PWM、4態(tài)IO接口、EEPROM等功能,但都沒有ADC這個高級功能。12是增強型功能的1T單片機,型號后面有“AD”的就有ADC功能的單片機。目前12系列是主流產(chǎn)品。15:15系列是STC公司最新推出的產(chǎn)品,最大的特別是內(nèi)部集成了高精度的R/C時鐘,可以完全不需要接外部晶振。
STC12C5A60S2單片機中包含中央處理器(CPU)、程序存儲器(Flash)、數(shù)據(jù)存儲器(SRAM)、定時/計數(shù)器、UART串口、串口2、I/O接口、高速A/D轉(zhuǎn)換、SPI接口、PCA、看門狗及片內(nèi)R/C振蕩器和外部晶體振蕩電路等模塊。STC12C5A60S2系列單片機幾乎包含了數(shù)據(jù)采集和控制中所需的所有單元模塊,可稱得上一個片上系統(tǒng)。
STC12C系列增強型單片機片上擴展了基本51單片機的功能,如提供了PCA/PWM接口,定時器能工作在1T模式下(基本51單片機的時鐘是Fosc的12分頻,1T模式下1分頻)。
PCA可以用于脈寬測量,但是,protues暫不支持該系列單片機的仿真功能,反復燒寫也挺麻煩,所以還是先用基本51單片機實現(xiàn)該功能,在后面的博文里在實現(xiàn)PCA測量脈寬。
實現(xiàn)思路如下:
TMOD最高位GATEn置位后,Tn啟動計數(shù)受INTn(Pin3.3)和TRn的共同影響:TRn為1,當INTn引腳輸入為高電平時,Tn才允許計數(shù)。利用這個功能可測量INTn上正脈沖的寬度。
1):1處 在上升沿之前,初始化TMOD,TRn=1;
2):2處 INTn引腳為高電平,開始計數(shù)測量脈寬;
3):3處 INTn引腳為低電平,測量結(jié)束停止計數(shù)TRn=0
再上仿真圖:
1)。信號發(fā)生器電平選5v方波。注信號發(fā)生器的反相端接地,否則正向端只輸出2.5v的方波(剩下的2.5v輸出反相方波,可以接到示波器上試試),INTn上永遠收不到高電平,達不到預期效果。
2).T0定時器做計數(shù)器使用,收到一個負脈沖產(chǎn)生溢出,啟動T1;
3).T0,T1全工作在方式2自動裝載計數(shù)值模式。
然后,上代碼:
工作頻率12Mhz
#include
#include
sbit P1_0 = P3^3;
#define MakeByte(target, Hi,Lo) \
do{ \
target |= (((Hi)《《4)|(Lo)); \
}while(0); \
#define SetTH(n,val) \
do{ \
TH##n = val; \
}while(0); \
#define SetTL(n,val) \
do{ \
TL##n = val; \
}while(0); \
#define EnableET(n) \
do{ \
ET##n = 0x01; \
IE |= 0x80; \
}while(0); \
unsigned int click;
unsigned int oneMs;
unsigned char getPlusWidth;
int main()
{
unsigned int totalus=0,maxPlusWidth=0;
P3 = 0xFF;
getPlusWidth = 0;
MakeByte(TMOD,0x0A,0x06);
SetTH(0,0xff);
SetTL(0,0xff);
SetTH(1,0x38);
SetTL(1,0x38);
EnableET(0);
EnableET(1);
TR0 = 0x01;
while(1)
{
while(!getPlusWidth);
//等待INT1至低
while(INT1==0x01);
//等待INT1至高電平
while(INT1==0x00);
//等待INT1至低電平,脈寬結(jié)束
while(INT1==0x01);
TR1 = 0x00;
totalus = 1000*(oneMs+(click*0.2))+(TL1-TH1);
oneMs = 0;
}
return 0;
}
//T0引腳上接受到負跳變
void IsrT0() interrupt 1
{
TR1 = 0x00;
getPlusWidth = 1;
TR1 = 0x01;
}
void IsrT1() interrupt 3
{
//每次進入中斷0.2ms
click++;
if(click == 5)
{
oneMs++;
click=0;
}
}
最后 上仿真結(jié)果:
500Hz的方波,脈寬981us
1kHz的方波,脈寬587us
2kHz方波,脈寬234us
一種很精確測量脈沖寬度的方法。
具體思想是:
用定時器的內(nèi)部資源(當GATE = 1時,計數(shù)器的停止和開始受TR和INT的電平共同控制),我們這里用定時器0 ,將外部脈沖接在INT0上,配置定時器0和外部中斷0。當脈沖是高電平時,計數(shù)器(TH0,TL0)計數(shù),當計數(shù)器溢出時,觸發(fā)定時器中斷。當脈沖為下降沿時,觸發(fā)外部中斷,此時停止計數(shù),所記下的時間也就是脈沖的寬度。
代碼如下:
#include 《reg51.h》
#include 《intrins.h》
#define uint unsigned int
#define uLint unsigned long int //長整型
uLint pulse_w = 0 ;//計算脈沖的時間,用長整型可以達到10的9次方us,如果用uint,最大只能達到65535us(還不到100ms)
sbit in = P3^2 ;
void Int0 (void) interrupt 0
{
pulse_w += TL0 ;
TL0 = 0 ;
}
void Time0(void) interrupt 1
{
pulse_w += 256 ;//計數(shù)寄存器溢出,直接加最大值
}
int main()
{
//初始化
TMOD = 0xA ; //定時器0,模式2,GATE0 = 1
TH0 = 0 ; //填初值
TL0 = 0 ;
TR0 = 0 ;
ET0 = 1 ;//開定時器0中斷
IT0 = 1 ;//外部中斷0下降沿觸發(fā)中斷
EX0 = 1 ;//開外部中斷0
EA = 1 ;//開總中斷
while(1)
{
if(in == 0)//見下面的解釋
TR0 = 1 ;
}
}
信號函數(shù):
signal void test(double cc)
{
port3 &= ~(0x1《《2) ;
swatch(1) ;
port3 |= (0x1《《2) ;
swatch(cc) ;
port3 &= ~(0x1《《2) ;
swatch(0.1) ;
_break_ = 1 ;
}
輸入波形(脈沖高電平1s)
查看變量的值(0xF4240 = 1000000)
注釋1:由于單片機復位后所有port都為高電平,所以如果不做一些措施的話,單片機一復位,計數(shù)器就會計數(shù),造成測量誤差。我的做法是:開始設(shè)TR0= 0,這樣port3.2就無法開啟計數(shù)器。當外部脈沖低電平時,我才讓TR0 = 1,這時port3.2才能開啟計數(shù)器,達到精準計時的要求
注釋2:單片機的晶振為12M,所以時鐘周期為1us
評論
查看更多