51单片机测量占空比

在《CAP功能测频率》一文中,我们讲了利用STC12C5608AD的CAP功能测量频率,这一节,我们讲利用CAP功能测量频率的占空比,下面的程序,是我在做一个显示汽车发动机点火喷油脉宽项目时做的程序。现在分享给大家:

/**************************************************************************
功能:测量频率的低电平保持时间,用来测量汽车喷油嘴喷油的时间,单位ms
硬件:STC12C5608AD+3位LED+TM1620+12M晶振+LM358+74HC14
****************************************************************************/
#include <stc12c5608ad.h>// 调用头文件,可以上官方下载STC12C5608AD下载头文件
#include <intrins.h>
#include <math.h>?????? //因为本例中,有用到modf;所以必须调用该头文件 ?

#define uint? unsigned int?? ? // 宏定义uint (0~65535)
#define uchar unsigned char? // 

#define WAIT_TIME? 0x01??? //mcu clock <24mhz // 定义Flash 操作等待时间
#define OPENUART 0 // 0 关闭串口, 1 打开串口

sbit STB =P3^2;??????? // 定义片选通讯口
sbit CLK =P3^3;??????? // 定义时钟通讯口
sbit DIO =P3^4;??????? // 定义数据输入/输出通讯口

sbit CheSu1 = P3^5;??? // 测试速度的引脚
sbit KEY1 = P1^7;

uchar bai_num,shi_num,ge_num;
uint CheSu;//表示低电平的时间,单位10us
//uint CS_F=0; // 上一个车速寄存器
uchar CheSu_Clr=0;

unsigned int cap_tmp;
//float xielv=1.0; // 车速与车速频率的斜率
//float chesu_f;
//uchar CheSu_error[5]={0};
//uchar cse_cnt=0;
//uchar jiao=0; // 车速校正开关

static uchar code LED_tab[12]={? // 定义数码管0~9数字码表
0x3f,??? //0B00111111,?????? //0
0x06,??? //0B00000110,?????? //1
0x5b,??? //0B01011011,?? ????? //2
0x4f,??? //0B01001111,?? ??? ? //3
0x66,??? //0B01100110,?? ????? //4
0x6d,??? //0B01101101,?? ??? ? //5
0x7d,??? //0B01111101,?? ??? ? //6
0x07,??? //0B00000111,?? ????? //7
0x7f,??? //0B01111111,?? ??? ? //8
0x6f,??? //0B01101111,?? ??? ? //9
0x40,?? ??? ??? ??? ??? ??? ? //-? ?
0x00?? ?
};

unsigned char out_data[2]={0x00};

void delay_ms(uint cyc)
{
?? ?//当将=1的时候,延时1ms
?? ?uint ii,jj;

?? ?for(jj=1;jj<=cyc;jj++)
?? ?{
?? ??? ?for(ii=0;ii<940;ii++)
?? ??? ?{
?? ??? ??? ?_nop_();
?? ??? ?}
?? ?}
}

void TM1620_Write(uchar wr_data)
{
?? ?uchar i;

?? ?for(i=0;i<8;i++)
?? ?{
?? ??? ?CLK = 0;
?? ??? ?if(wr_data&0x01)DIO = 1;
?? ??? ?else DIO = 0;
?? ??? ?CLK = 1;
?? ??? ?wr_data>>=1;
?? ?}??????????????? ?
}

void Write_COM(unsigned char cmd)?? ??? ?//发送命令字
{
?? ?STB = 0;
?? ?TM1620_Write(cmd);
?? ?STB = 1;
}

void init_TM1620(void)
{
?? ?Write_COM(0x44);? // 01000000准备写数据到显示寄存器,普通模式,自动地址增加
?? ?STB=0;
?? ?TM1620_Write(0xc0);?? ? // 11000000 设置显示地址从0开始
?? ?TM1620_Write(0x00);?? ?? // 所有显示为灭
?? ?STB=1;
?? ?STB=0;
?? ?TM1620_Write(0xc2);
?? ?TM1620_Write(0x00);
?? ?STB=1;
?? ?STB=0;
?? ?TM1620_Write(0xc4);
?? ?TM1620_Write(0x00);
?? ?STB=1;
?? ?Write_COM(0x8a);? // 最亮?? ?10001111 设置消光脉冲14/16 显示开
}

void led_show()
{
//?? ?Write_COM(0x44);? // 01000000准备写数据到显示寄存器,普通模式,自动地址增加
?? ?STB=0;
?? ?TM1620_Write(0xc0);?? ? // 11000000 设置显示地址从0开始
?? ?TM1620_Write(LED_tab[bai_num]);?? ?? // 所有显示为灭
?? ?STB=1;
?? ?STB=0;
?? ?TM1620_Write(0xc2);?? ? // 11000000 设置显示地址从0开始
?? ?TM1620_Write(LED_tab[shi_num]);?? ?? // 所有显示为灭
?? ?STB=1;?? ?
?? ?STB=0;
?? ?TM1620_Write(0xc4);?? ? // 11000000 设置显示地址从0开始
?? ?TM1620_Write(LED_tab[ge_num]);?? ?? // 所有显示为灭
?? ?STB=1;
}

void CAP_Init(void)
{
?? ?// T0、T1打开,T0做PCA时钟,T1做定时器,在中断里喂狗和给CheSu清零
?? ?TMOD=0x12;? // T0工作在8位自动重载模式,T1工作在16位模式
?? ?TH0=0XF6;?? ??? ? //12M下的值,10us
?? ?TL0=0XF6;
?? ?TR0=1;
?? ?TH1=0X00;
?? ?TL1=0X00;
?? ?ET1=1;
?? ?TR1=1;

?? ?// PCA计数器打开
?? ?CMOD = 0X04;?? // 选择T0的溢出为PCA计数时钟
?? ?CCAPM1 = 0X11; // CAPN0 = 1; 下降沿捕获。ECCF0 = 1; 开捕获中断。
?? ?CL = 0;
?? ?CH = 0; // PCA计数器清零
?? ?CCAP1L = 0;
?? ?CCAP1H = 0; // 捕获寄存器清零
?? ?EPCA_LVD = 1; // 开PCA中断
//?? ?CR = 1;
}

/********************************************************************/
/**********************? T1中断服务函数? ****************************/
/********************************************************************/
// 65.536毫秒进一次中断
void T1_SER() interrupt 3
{
?? ?CheSu_Clr++;
?? ?WDT_CONTR=0x3C; // 1.1377s不喂狗复位
?? ?if(CheSu_Clr>=17) // 1秒钟没有进PCA中断函数清CheSu_Clr,车速归0
?? ?{
?? ??? ?out_data[0]=0;
?? ??? ?out_data[1]=0;
?? ??? ?CheSu_Clr=0;? // 车速为0标志
?? ??? ?CheSu=0;
?? ?}?? ?
}

// PCA中断服务函数
void PCAIRQ(void) interrupt 6
{?? ?
?? ?if(CCF1==1)? // 如果是PCA1捕获产生的中断
?? ?{
?? ??? ?CCF1=0;
?? ??? ?if(CCAPM1==0X11)
?? ??? ?{
?? ??? ??? ?CR = 1; // 打开PCA计数器
?? ??? ??? ?CCAPM1 = 0X21;// 配置为上升沿触发中断
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?CR = 0;// 关闭PCA计数器
?? ??? ??? ?CCAPM1 = 0X11; // 配置为下降沿触发中断
?? ??? ??? ?out_data[0]=CCAP1L;
?? ??? ??? ?out_data[1]=CCAP1H;
?? ??? ??? ?CH=0;
?? ??? ??? ?CL=0;
?? ??? ??? ?// 获取当前低电平保持时间数据
?? ??? ??? ?cap_tmp=out_data[1]<<8;
?? ??? ??? ?cap_tmp+=out_data[0];?? ?
?? ??? ??? ?CheSu = cap_tmp;
?? ??? ?}
? } 
?? ?else if(CF==1) // 如果是PCA溢出产生的中断
?? ?{
?? ??? ?CF = 0;
?? ?}
?? ?CheSu_Clr=0;
}

void led_xian(uint led_val)
{
?? ?if(led_val<1000) // 小于1000,显示为0.00格式,单位毫秒
?? ?{
?? ??? ?bai_num=(led_val/100);
?? ??? ?shi_num=(led_val%100)/10;
?? ??? ?ge_num=(led_val%100)%10;
?? ??? ?STB=0;
?? ??? ?TM1620_Write(0xc0);?? ? // 11000000 设置显示地址从0开始
?? ??? ?TM1620_Write(LED_tab[bai_num]|0x80);?? ?? // 所有显示为灭
?? ??? ?STB=1;
?? ??? ?STB=0;
?? ??? ?TM1620_Write(0xc2);?? ? // 11000000 设置显示地址从0开始
?? ??? ?TM1620_Write(LED_tab[shi_num]);?? ?? // 所有显示为灭
?? ??? ?STB=1;?? ?
?? ??? ?STB=0;
?? ??? ?TM1620_Write(0xc4);?? ? // 11000000 设置显示地址从0开始
?? ??? ?TM1620_Write(LED_tab[ge_num]);?? ?? // 所有显示为灭
?? ??? ?STB=1;
?? ?}
?? ?else // 大于等于1000,显示为00格式,单位毫秒
?? ?{
?? ??? ?bai_num = 11;
?? ??? ?shi_num = (led_val/100)/10;
?? ??? ?ge_num = (led_val/100)%10;
?? ??? ?led_show();
?? ?}
}

void main()
{
?? ?unsigned int ms_cnt=0;

?? ?CLK = 1;?? ??? ??? ?// 上拉TM1629B通信时钟引脚
?? ?STB = 1;?? ??? ??? ?// 上拉TM1629B通信片选引脚
?? ?DIO = 1;?? ??? ??? ?// 上拉TM1629B通信数据引脚

?? ?init_TM1620();?? ?? // 初始化LED控制芯片
?? ?bai_num=11;
?? ?shi_num=11;
?? ?ge_num=0;
?? ?led_show();

?? ?delay_ms(1200);
?? ?CAP_Init();
?? ?EA = 1;

?? ?while(1)
?? ?{
?? ??? ?ms_cnt++;
?? ??? ?delay_ms(1);
?? ??? ?if(ms_cnt>300) // 300毫秒显示一次数据
?? ??? ?{
?? ??? ??? ?ms_cnt=0;?? ??? ?
?? ??? ??? ?if(CheSu<1000)
?? ??? ??? ?{?? ?
?? ??? ??? ??? ?led_xian(CheSu);
?? ??? ??? ?}
?? ??? ?}
?? ?}
}

KEIL工程源码: