📄 24bit ad sample.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 + -