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

📄 24bit ad sample.c

📁 24位AD转换程序例程
💻 C
字号:
/* ****************************************************************
** 功能描述: SPI串行采样三路AD输入程序
*************************************************************** */
#include	"pic18.h"		// 所有PIC18系列的头文件
#define count 100			// 定义采样个数

/* ****************************************************************
** 定义全局共用体data,用于将字符形合成为长整形
*************************************************************** */
union data
{
struct
	{	
	unsigned char low;			// 低位(8位字符变量,一个字节)
	unsigned char mid;			// 中位
	unsigned char high;			// 高位
	}shortdata;
unsigned long longdata;			// 32位长整形,四个字节 
};

/* ****************************************************************
** 定义全局变量
*************************************************************** */
unsigned char i=count;			// 全局计数变量
unsigned long ADx[count];		// 存放ADx模块转换数据
unsigned long ADy[count];		// 存放ADy模块转换数据
unsigned long ADz[count];		// 存放ADz模块转换数据
unsigned long *ADxP=ADx;		// 指向数组ADx首地址的指针变量
unsigned long *ADyP=ADy;		// 指向数组ADy首地址的指针变量
unsigned long *ADzP=ADz;		// 指向数组ADz首地址的指针变量


/* ****************************************************************
** 函 数 名: initial()
** 功能描述: 系统初始化子程序,放在程序首部
*************************************************************** */
void	initial()
{
	INTCON=0x00;			// bit7-bit0:关总中断 
	ADCON1=0x07;			// 设置数字输入输出口,(复位后与A/D模块有关的引脚都设置为模拟输入)
	PIE1=0x00;				// PIE1 的中断不使能 			
	PIE2=0x00;				// PIE2 的中断不使能 
}

/* ****************************************************************
** 函 数 名: initialPORTA()
** 功能描述: POARTA端口初始化子程序,放在程序首部
*************************************************************** */

void initialPORTA()
{
	TRISA&=0xF8;		// 设置RA0,RA1,RA2为数字输出口
	TRISA=0xF8;
}


/* ****************************************************************
** 函 数 名: initialPORTB()
** 功能描述: POARTB端口初始化子程序,放在程序首部
*************************************************************** */
void initialPORTB()
{
	TRISB&=0xEB;		// 设置RB4,RB2为数字输出口
}

/* ****************************************************************
** 函 数 名: initialPORTC()
** 功能描述: POARTC端口初始化子程序,放在程序首部
*************************************************************** */
void initialPORTC()
{
	TRISC|=0x07;		// 设置RC0,RC1,RC2为数字输入口
}

/* ****************************************************************
** 函 数 名: SPIitial()
** 功能描述: SPI初始化子程序
*************************************************************** */
void	SPIinitial()
{
	TRISC&=0xd7;			// SDO(RC5)引脚为输出,SCK(RC3)引脚为输出
	TRISC4=1;				// SDI(RC4)引脚为输入
	SSPCON1=0x31;			// SSPEN=1;CKP=1,低电平有效;FOSC/16 (A/D模块的最大传输速度为Xin/5)
	SSPSTAT=0xC0;			// 时钟下降沿发送数据
	SSPIF=0;				// 清除SSPIF中断标志
}

/* ****************************************************************
** 函 数 名: INTitial()
** 功能描述: INT初始化子程序
*************************************************************** */
void INTitial()
{
	TRISB0=1;				// 设置RB0为数字输入口	
	INT0IE=1;				// 使能INT0中断
	INT0IF=0;				// 清INT0中断标志
	INTEDG0=0;				// INT0下降沿中断
	IPEN=1;					// 使能中断优先级
}

/* ****************************************************************
** 函 数 名: SPIOUT()
** 功能描述: SPI发送数据子程序
*************************************************************** */
void  	SPIOUT(unsigned char data)
{
	SSPBUF=data;			// 启动 SPI 发送 
	do
	{
	  ;
	}while(SSPIF==0);		// 等待SPI 发送完成 
	SSPIF=0;				// 清SPI 发送完成标志 
							// 从数据传输完成到函数调用结束已用了3个指令周期
}

/* ****************************************************************
** 函 数 名: SPIIN()
** 功能描述: SPI接收数据子程序
*************************************************************** */
char 	SPIIN()
{
	unsigned char data;
	SSPBUF=0;				// 启动SPI,此操作用于清除SSPSTAT的BF位 
	do
	{
	    ;
	}while(SSPIF==0);		// 查询数据接收完毕否?
	SSPIF=0;				// 清除SSPIF标志
	data=SSPBUF;
	return data;			// 返回接收到的数据
						    // 从数据读入到返回至少用了4个指令周期
}

/* ****************************************************************
** 函 数 名: Delay()
** 功能描述: 延时函数
*************************************************************** */
void Delay(unsigned int d)
{
	while(--d)				// 4MHz时钟,延时大概10*d微秒
	{
		;
	}
}

/* ****************************************************************
** 函 数 名: ADSelfCalibration()
** 功能描述: A/D模块自检子程序,由cs指定自检的AD模块(0xfe,0xfd,0xfb,
** 			 分别选择ADx,ADy,ADz),偏置寄存器和全比例寄存器的值分别
**			 由指针offlong,fulllong返回
*************************************************************** */
void ADSelfCalibration(unsigned char cs,unsigned long *offsetP,unsigned long *fullscaleP)
{
	union data offsetUN,fullscaleUN;	// 定义两个共用体
	PORTA=cs;				// 选择AD1210模块			
	cs=~cs;					// 将cs按位取非
	CLRWDT();				// 清看门狗计数器
	do
	{
		;
	}while(PORTC&&cs);		// 判断AD1210模块是否准备好
	
	NOP();					// 间隔5.5个AD时钟周期
	NOP();
	SPIOUT(0x64);			// 向Command Register 写入4个字节,先写高位
	NOP();					// 间隔5.5个AD时钟周期,一条指令4个单片机时钟周期
	SPIOUT(0x12);			// REFout关闭,单极输出,使能SDOUT
	SPIOUT(0x20);			// 设置自检模式
	SPIOUT(0x43);			// TURBO MODE为4
	SPIOUT(0x0c);			// DATA RATE=20,Decimation ratio=0x30c
	NOP();					// 间隔5个AD时钟周期
	CLRWDT();				// 清看门狗计数器
	do
	{
		;
	}while(PORTC&&cs);		// 判断AD1210模块是否自检完毕

	NOP();					// 间隔5.5个AD时钟周期
	NOP();
	
	SPIOUT(0xc8);			// 读 Offset register
	NOP();					// 间隔5.5个AD时钟周期
	offsetUN.shortdata.high=SPIIN();	// 读入偏置寄存器高位字节
	offsetUN.shortdata.mid=SPIIN();		// 读入偏置寄存器中位字节
	offsetUN.shortdata.low=SPIIN();		// 读入偏置寄存器低位字节
	*offsetP=offsetUN.longdata;			// 将偏置寄存器值送出

	NOP();					// 间隔20.5个AD时钟周期
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();

	SPIOUT(0xcc);						// 读 fullscale register
	NOP();								//
	fullscaleUN.shortdata.high=SPIIN();	// 读入全比例寄存器高位字节
	fullscaleUN.shortdata.mid=SPIIN();	// 读入全比例寄存器中位字节
	fullscaleUN.shortdata.low=SPIIN();	// 读入全比例寄存器低位字节
	*fullscaleP=fullscaleUN.longdata;	// 将全比例寄存器值送出 
}

/* ****************************************************************
** 函 数 名: ADSetRegister()
** 功能描述: 设置A/D模块偏置寄存器和全比例寄存器子程序,
** 			 cs指定自检的AD模块(0xfe,0xfd,0xfb,分别选择ADx,ADy,ADz)
*************************************************************** */
void ADSetRegister(unsigned char cs)
{
	unsigned char j;
	unsigned long getoff=0,getfull=0;
	unsigned long *getoffP=&getoff,*getfullP=&getfull;
	union data setoffUN,setfullUN;
	setoffUN.longdata=0;
	setfullUN.longdata=0;
	for(j=5;--j;)							// 自检4次
	{
		ADSelfCalibration(cs,getoffP,getfullP);		// 自检
		setoffUN.longdata+=getoff;			// 将偏置寄存器自检值求和
		setfullUN.longdata+=getfull;		// 将全比例寄存器自检值求和
	}
	setoffUN.longdata>>2;					// 偏置寄存器自检值求平均
	setfullUN.longdata>>2;					// 全比例寄存器自检值求平均

	PORTA=cs;				// 选择AD1210模块			
	cs=~cs;					// 将cs按位取非
	CLRWDT();				// 清看门狗计数器
	do
	{
		;
	}while(PORTC&&cs);		// 判断AD1210模块是否准备好

	NOP();					// 间隔5.5个AD时钟周期
	NOP();
	
	SPIOUT(0x48);			// 写 Offset register
	NOP();					// 间隔5.5个AD时钟周期
	SPIOUT(setoffUN.shortdata.high);	// 写到偏置寄存器高位字节
	SPIOUT(setoffUN.shortdata.mid);		// 写到偏置寄存器中位字节
	SPIOUT(setoffUN.shortdata.low);		// 写到偏置寄存器低位字节

	NOP();					// 间隔20.5个AD时钟周期
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();
	NOP();

	SPIOUT(0x4c);						// 写 fullscale register
	NOP();								//
	SPIOUT(setfullUN.shortdata.high);	// 写到全比例寄存器高位字节
	SPIOUT(setfullUN.shortdata.mid);	// 写到全比例寄存器中位字节
	SPIOUT(setfullUN.shortdata.low);	// 写到全比例寄存器低位字节
}	
	
	
/* ****************************************************************
** 函 数 名: ADread()
** 功能描述: 读取Data Output Register 数据,
*************************************************************** */
void ADread( unsigned long *dorlong)
{
	union data dor;			
	SPIOUT(0xc0);					//读Data Output Register 数据
	NOP();							//
	dor.shortdata.high=SPIIN();		//读入数据输出寄存器高位字节
	dor.shortdata.mid=SPIIN();		//读入数据输出寄存器中位字节
	dor.shortdata.low=SPIIN();		//读入数据输出寄存器低位字节
	*dorlong=dor.longdata;			//将数据输出寄存器值送出
}

/* ****************************************************************
** 函 数 名: interrupt HI_ISR()
** 功能描述: 高优先级中断子程序--int0中断
*************************************************************** */
void interrupt HI_ISR()
{
	if(INT0IF==1)
	{
		INT0IF=0;			// 清INT0中断标志
		NOP();				// 间隔5.5个AD时钟周期

		PORTA=0xfe;			// 选择ADx模块
		NOP();				// 间隔5.5个AD时钟周期
		NOP();	
		ADread(ADxP);		// 读ADx模块转换数据到数组
		ADxP++;				// 指针加1,指向数组下一个位置

		PORTA=0xfd;			// 选择ADy模块
		NOP();				// 间隔5.5个AD时钟周期
		NOP();	
		ADread(ADyP);		// 读ADy模块转换数据到数组
		ADyP++;

		PORTA=0xfb;			// 选择ADz模块
		NOP();				// 间隔5.5个AD时钟周期
		NOP();	
		ADread(ADzP);		// 读ADz模块转换数据到数组
		ADzP++;				// 指针加1,指向数组下一个位置

		if(i&&0x10)			// 每读16个数据就转换一次蓝灯的开关状态
		{
			if(RB4==0)
				RB4=1;
			else
				RB4=0;
		}
		
		
		if(--i==0)
		{
			i=count;			// 复位计数值
			ADxP=ADx;			// 指向数组ADx首地址的指针变量
			ADyP=ADy;			// 指向数组ADy首地址的指针变量
			ADzP=ADz;			// 指向数组ADz首地址的指针变量
			RB2=1;				// 数据满100则黄灯亮
		}
	}
	CLRWDT();					// 清看门狗计数器	
}


main()					
{
	initial();				// 系统初始化子程序 

	initialPORTA();			// 初始化POARTA端口
	initialPORTB();			// 初始化POARTB端口
	initialPORTC();			// 初始化POARTC端口

	SPIinitial();			// SPI初始化子程序
	INTitial();				// INT初始化子程序
	
	WDTCON=0;				// 禁止看门狗

	PORTB=0x00;				// 关蓝色和黄色指示灯

	ADSetRegister(0xfe);	// 设置ADx模块的偏置寄存器和全比例寄存器
	ADSetRegister(0xfd);	// 设置ADy模块的偏置寄存器和全比例寄存器
	ADSetRegister(0xfb);	// 设置ADz模块的偏置寄存器和全比例寄存器
	PORTB=0x14;				// 开蓝色和黄色指示灯
	Delay(0xffff);			// 延时,以观察指示灯
	PORTB=0x00;				// 关蓝色和黄色指示灯
	INTCON|=0x80;			// 开总中断
	while(1)
	{
		CLRWDT();			// 等待中断的发生
	}
}

⌨️ 快捷键说明

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