⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adc_sub.c

📁 ADC数据采集实例
💻 C
字号:


#include		<pic.h>
#include 		<math.h>
#include 		<stdio.h>

/*
//该程序用于测电网的交流电压有效值,最后的结果将在4个LED上显示,保留
//1位小数。
//为了保证调试时数据运算的精确性,需要将PICC的double型数据选成32位
//公式:若相邻两采样的时间间隔相等,即ΔTm为常数ΔT,考虑到N=(T/ΔT)+1,则有
 
式(1)就是根据一个周期各采样瞬时值及每周期采样点数计算电压信号有效值的公式。
计算步骤:
1:   先计算每次采样数据对应的实际电压值(要跟据A/D,基准参数确定),再求其平方
2:再将N次采样实际电压值的平方值求和,然后求其平均值
3:将平均值开方,得出的数值就是电压的有效值了。


注意:此采用的A/D器件应有允许‘正负输入’这一量程。
=========================================================================*/

typedef union	adres
		{
		int	y1;
		unsigned char adre[2];
		}adresult;				//定义一个共用体

	 int	re[40];			//定义存放A/D转换结果的数组,在bank3中
	unsigned char k,data;		//定义几个通用寄存器
	double	squ ,squad;		//平方寄存器和平方和寄存器,squ又通用为存储其
								//它数值
	int	uo;
bank1	unsigned  char	s[4];	//此数组用于存储需要显示的字符的ASII码
const	  char	table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90};
//不带小数点的显示段码表
const	  char  table0[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//带小数点的显示段码表
//A/D转换初始化子程序
void		adinitial()
{
	ADCON0=0x41;			//选择A/D通道为RA0,且打开A/D转换器
		      				//在工作状态,使A/D转换时钟为8Tosc
	ADCON1=0X8E;			//转换结果右移,及ADRESH寄存器的高6位为"0"
	                 		//把RA0口设置为模拟量输入方式
	ADIE=1;				//A/D转换中断允许
	PEIE=1;					//外围中断允许
	TRISA0=1;				//设置RA0为输入方式
}
//spi方式显示初始化子程序
void 			SPIINIT()
{
	PIR1=0;
	SSPCON=0x30;	
	SSPSTAT=0xC0;
//设置SPI的控制方式,允许SSP方式,并且时钟下降沿发送,与"74HC595,当其
//SCLK从低到高跳变时,串行输入寄存器"的特点相对应
	TRISC=0xD7;			//SDO引脚为输出,SCK引脚为输出
	TRISA5=0;				//RA5引脚设置为输出,以输出显示锁存信号
}
//系统其它初始化子程序
void	initial()
{
	CCP2IE=0;				//禁止CCP中断
	SSPIE=0;				//禁止SSP中断
	CCP2CON=0X0B;		//初始化CCP2CON,CCP2为特别事件触发方式
	CCPR2H=0X01;
	CCPR2L=0XF4;			//初始化CCPR2寄存器,设置采样间隔500 μs,
							//一个周期内电压采40个点
}
//中断服务程序
void		interrupt		adint(void)
{
	CCP2IF=0;
	ADIF=0;				//清除中断标志
	adresult.adre[0]=ADRESL;
	adresult.adre[1]=ADRESH;	//读取并存储A/D转换结果,A/D转换的结果
				  			//通过共用体的形式放入了变量y1中 
	re[k]=adresult.y1;			//1次A/D转换的结果存入数组
	k++;					//数组访问指针加1
}
//SPI传送数据子程序
void  	SPILED(data)
{
	SSPBUF=data;			//启动发送
	do{
	}while(SSPIF==0);
	SSPIF=0;
}
//主程序
main( )
{
	adinitial();				//A/D转换初始化
	SPIINIT();				//spi方式显示初始化
	initial();					//系统其它初始化	
	while(1){
		k=0;				//数组访问指针赋初值	
		TMR1H=0X00	;
		TMR1L=0X00;		//定时器1清0
		ei();				//中断允许
		T1CON=0X01;		//打开定时器1	
		while(1){
			if(k==40)	break;	//A/D转换次数达到40,则终止
		}
		di();				//禁止中断
	for(k=0;k<40;k++)re[k]=re[k]-0X199;//假设提升电压为2 V,对应十六进制数199H,
							//则需在采样值的基础上减去该值
	for(k=0,squad=0;k<40;k++)	{
		uo=re[k];
		squ=(double)uo;		//强制把采得的数据量转换成双精度数,以便运算
		squ=squ*5/1023;		//把每点的数据转换成实际数据(5v基准,12BIT A/D)
		squ=squ*squ;			//求一点电压的平方
		squad=squad+squ;	  	;求平方和
	}						//以上求得40点电压的平方和,存于寄存器 squad中
	squ=squad/40;			//求得平均值
	squ=sqrt(squ);			//开平方,求得最后的电压值
	squ=squ*154.054;			//通过变压器的变比和分压电阻分配确定该系数
							//以上得到了实际电网的电压值
	squ=squ*10;				//为了保证显示的小数点的精度,先对电压值乘以10
	uo=(int)squ;				//强制把U转换成有符号整型量
	sprintf(s,"%4d",uo);		//通过sprintf函数把需要显示的电压数据转换成
							//ASII码,并存于数组S中
	RA5=0;					//准备锁存
	for(k=0;k<4;k++){
		data=s[k];
		data=data&0X0F;		//通过按位相与的形式把ASII码转换成BCD码
		if(k==2)	data=table0[data];//因为squ已乘以10,则需在第2位打小数点
		else	data=table[data];	// table0存储带小数点的显示段码,
				  			//table存储不带小数点的显示段码
		SPILED(data);		//发送显示段码
	}
	for(k=0;k<4;k++)	{
		data=0xFF;
		SPILED(data);	//连续发送4个DARK,使显示看起来好看一些,这点与
						//该实验板的LED分布结构有关
	}
	RA5=1;				//最后给一个锁存信号,代表显示任务完成 	
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -