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工程源码: