一、C8051F学习日记 今天开始每天把学习C8051F的感受记下来 今天上传一个AD采集交流电的程序50HZ的交流电经过精密整流以后每个周期单通道采集800个点分两个通道采集电压和电流并计算S,P,Q,相位角g ; 感觉玩C8051F的AD好爽啊 还有DA 功能强啊 就是爽 /******************************************************************* C8051F020 AD采集 2006.09.26 *******************************************************************/ /************************预定义************************************/ #i nclude
#i nclude #i nclude #i nclude /******************************************************************* 定义IO口和变量 *******************************************************************/ sbit LCDBUSY = P3^0; //LCD忙信号位 sbit REQ = P3^1; //LCD请求信号位 sbit RES = P3^2; //LCD复位信号位 sfr16 ADC0 = 0xbe; unsigned int xdata ADC0_data1[800]; //AD通道一采集数据存放数组 unsigned int xdata ADC0_data2[800]; //AD通道二采集数据存放数组 unsigned int data ADC0_data_n; //AD采集次数 unsigned int data ADC0_data_n1; //通道一采集次数 unsigned int data ADC0_data_n2; //通道二采集次数 bit m;//AD采集完标志 /******************************************************************* 函数声明 *******************************************************************/ void Sjcl(void);//AD采集完100次数据处理函数 void ADC0_ISR(void);//ADC0中断函数声明 void write_data(unsigned char writedata);//写数据到LCD void send_ascii8(unsigned char x,unsigned char y,unsigned char ascii);//显示8*8ASCII /******************************************************************** 子函数定义 ********************************************************************/ void delay_us(int timer)//us沿时 { timer*=20;//时钟周期调整 for(;timer>0;timer--) _nop_(); } void delay_ms(int i)//ms沿时 { for(;i>0;i--) delay_us(1000); } void lcd_init(void)//lcd初始化 { RES=0; delay_ms(20); RES=1; REQ=0; LCDBUSY=0; } /******************************************************************** 系统初始化函数 ********************************************************************/ void UART_Init() { SCON0 = 0x50; //使能UART0并允许接收 } void Timer_Init() { CKCON = 0x10; TCON = 0x40; TMOD = 0x20; TH1 = 0xB8; //用定时器3做为AD0的启动转换标志每100us启动一次采集, TMR3CN = 0x04; //使用系统时钟12分频做为定时器3的时钟源(22.1184M) TMR3RLL = 0xd1; //T1使用系统时钟并产生9600的波特率用与UART0 TMR3RLH = 0xFF; TMR3L = 0xd1; TMR3H = 0xFF; } void ADC_Init() { ADC0CF = 0x40; //ADC0为定时器3益处采集方式,时钟频率为2.5M, ADC0CN = 0x04; //增益为1,数据为右对齐方式 AMX0SL=0X00; } void Voltage_Reference_Init() { REF0CN = 0x03; //ADC0的参考电压来自内部增益 } void Port_IO_Init() //IO口初始化 { P0MDOUT = 0x01; //P0.0,P0.1做为UART0的通信引脚,其中TX0为推拉方式 P3MDOUT = 0x06; //P3.0为BUSY读取引脚,设为开漏方式 //P3.1为请求标志位设为推拉方式 //P3.2为复位信号脚设置为推拉方式 P74OUT = 0x03; //P4为液晶数据线设为推拉方式 XBR0 = 0x04; XBR2 = 0x40; } void Oscillator_Init()//使用外部晶振22.1184M { int i = 0; OSCXCN = 0x67; for (i = 0; i < 3000; i++); // Wait 1ms for initialization while ((OSCXCN & 0x80) == 0); OSCICN = 0x08; } void Interrupts_Init() { EIE2 = 0x02; //允许ADC0中断 } void Init_Device(void) { Timer_Init(); UART_Init(); ADC_Init(); Voltage_Reference_Init(); //初始化主程序 Port_IO_Init(); Oscillator_Init(); Interrupts_Init(); } //end init// /**************************************************************************** 主函数定义开始 *****************************************************************************/ void main(void) { WDTCN=0xde; WDTCN=0xad; //关看门狗 Init_Device(); lcd_init(); AD0EN=1; delay_ms(5); EA=1; TI0=1; while(1) { if(m==1) { m=0; TMR3CN&=0xFB; //关定时器3 Sjcl(); //处理数据 TMR3CN|=0X04; //开定时器3 } } } /**************************************************************************** ADC0中断处理 ****************************************************************************/ void ADC0_ISR(void) interrupt 15 { ADC0CN&=0xdf; if(ADC0_data_n%2==0) { ADC0_data1[ADC0_data_n1] = ADC0; ADC0_data_n1++; AMX0SL = 0x01; } else { ADC0_data2[ADC0_data_n2]=ADC0; ADC0_data_n2++; AMX0SL=0x00; } ADC0_data_n++; if(ADC0_data_n==1600)//两路采集完800点 { m=1; } } /**************************************************************************** 数据采集完处理函数 ****************************************************************************/ void Sjcl(void) { /*unsigned int j;*/ /*unsigned char xdata lcd_senddata[4];//四位LCD显示数据*/ unsigned int i; unsigned long data ADC0_dataadd=0;//采集完毕的累加计算值 unsigned long data a=0; unsigned long data b=0; float data c; float data d; float data P_dataadd=0; float data U=0; float data I=0; float data S=0; float data P=0; float data Q=0; float data COSg=0; //通道一数据处理 for(i=0;i<=ADC0_data_n1;i++) { a=ADC0_data1[i]; ADC0_dataadd=ADC0_dataadd+a*a; } U=ADC0_dataadd/ADC0_data_n1;//取平均值 U=sqrt(U);//取平方根值 U=(U*2.451)/0x0fff;//计算实际电压值 //通道二数据处理 ADC0_dataadd=0; for(i=0;i<=ADC0_data_n2;i++) { a=ADC0_data2[i]; ADC0_dataadd=ADC0_dataadd+a*a; } I=ADC0_dataadd/ADC0_data_n2;//取平均值 I=sqrt(I);//取平方根值 I=(I*2.451)/0x0fff;//计算实际电压2值 S=U*I; for(i=0;i<=ADC0_data_n1;i++) //计算P值 { c=((float)ADC0_data1[i]*2.451)/0x0fff; d=((float)ADC0_data1[i]*2.451)/0x0fff; P_dataadd=P_dataadd+c*d; } P=P_dataadd/ADC0_data_n1;//取平均值 Q=sqrt(S*S-P*P);//计算Q值 COSg=P/S;//计算cosg值 printf("************************************\n"); delay_ms(10); printf("U=%.3fv I=%.3fv\n",U,I); delay_ms(10); printf("S=%.3fw P=%.3fw Q=%.3fw\n",S,P,Q); delay_ms(10); printf("COSg=%.3f\n",COSg); delay_ms(10); ADC0_data_n=0; ADC0_data_n1=0; ADC0_data_n2=0; } 二、C8051F020中ADC的使用方法 [ 2006-9-23 22:12:48 | By: huolf ] void init_vref(void) { REF0CN=0x03; //0x03 //允许参考电压发生器(b1)及其缓冲器x2(b0),参考电压从VREF引脚输出 //ADC0参考电压取自VREF0引脚(b4),ADC1参考电压取 自VREF1引脚(b3);禁止并使用外部参考是0x02 } void init_adc0(void) //系统时钟=12M { ADC0CF=0x28; //ADC0配置寄存 器,设置转换时钟(SAR<=2.5M)和内部放大器增益,SAR转换时钟 //=系统时钟/(b7-b3)=2M,内部放大器增益=1(b2-b0) AMX0SL=0x00; //模拟输入通道选 择寄存器(b3-0), ADC0CN=0x80; //ADC0控制寄存 器,允许ADC(b7),向AD0BUSY写1启动ADC(b3-b2) AMX0CF=0x00; //模拟输入方式配 置寄存器,(b3-0=0:AIN0-7是独立的单端输入,否则成队配置 //为差分输入),对于被配置成差分输入的通道,ADC数 据字格式为2的补码 EIE2=EIE2|0x02; //允许ADC0中 断,EADC0=1,EIE2.1=1 } void adc0(void) interrupt 15 using 3 //ADC0中断服务程序 { if(AD0INT) { AD0INT=0; adc0_result=ADC0H; adc0_result=adc0_result<<8; adc0_result=(adc0_result|ADC0L)&0x0fff; //020是12位ADC adc0_over=1; } } uint start_adc0(uchar channel,uchar adc_time)//adc_time是参与取平均的次数 { uchar xdata i,j; ulong xdata n=0; for(j=0;j<40;j++) { wdog=1; for(i=0;i=0;i--) for(j=255;j>=0;j--); } /*************************************************************/ void SYSCLK_Init (void) { int i; OSCXCN=0x67; for(i=255;i>=0;i--); while (!(OSCXCN & 0x80)) ; //11.059m hz OSCICN=0x88; } void UART0_Init (void) { SCON0 = 0x50; // SCON0: mode 1, 8-bit UART, enable RX TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload TH1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate TL1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate TR1 = 1; // start Timer1 CKCON |= 0x10; // Timer1 uses SYSCLK as time base PCON |= 0x80; // SMOD00 = 1 TI0 = 1; // Indicate TX0 ready } void init_port() //初始化端口 { P1 = 0xFF; P2 = 0xFF; P3 = 0xFF; P3MDOUT=0xff; //pull-push MODE P2MDOUT=0x00; //open-drain MODE P1MDOUT=0xff; //pull-push MODE } void main(void) //initial micro controller { unsigned char i; WDTDISABLE; SYSCLK_Init(); XBR0 = 0x04; // XBAR0: Initial Reset Value XBR1 = 0x04; // XBAR1: Initial Reset Value XBR2 = 0x40; // XBAR2: Initial Reset Value init_port(); UART0_Init (); P2MDOUT=0x00; P2=0xff; //接受数字输入 while(1) { for(i=0xff;i>0;i--) { P2MDOUT=0x00; P2=0xff; P1=i; printf("Now P2=%x\n",P2); DELAY(); } } }