本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:Phoenix_dz9WiU
CS1180是高精度、低功耗模数转换芯片。其分辨率为 20bit,有效分辨率可达 19 位。可以广泛使用在工艺控制、量重、液体/气体化学分析、血液分析、智能发送器、便携测量仪器领域。
本次主要以智能变送器为主 采集电压电流值稳控
首先我们看一下管脚说明
主要以spi通信方式为主,我这里是用到两个adc芯片 SDI、SDO、SCLK、三线共用,以片选不同采集不同路的数据
接下来看规格书要求的通信时序
按照要求编写即可
接下来就是我们要操作的寄存器 以下是主要寄存器
SETUP和MUX在初始化中配置,增益倍数选择,默认是0,测试中4倍也是可以读到的
这里要注意ACR寄存器使用单极性输出,时钟选择/256,这个要根据你的时钟选择判断,转换范围选择也要选择VERF/2的,是有哪位我的外部电路输入电压不同导致选择的不同 其他位用默认值0即可
ODAC寄存器配置为0x30,这里我也没有特别理解,网上搜到的驱动是这样写的,可能与你本身的硬件电路有关,我买的是cs1180集成板,里面电路已经确定的,如果各位知道原因的话,也教一下我,谢谢
主要的内容就是以上,接下来直接看代码,如有疑问和问题,敬请指出
`
//寄存器地址定义
define SETUP 0X00//PGA 及BO//cs 控制
define MUX 0X01//输入通道选择
define ACR 0X02//模拟电路控制
define ODAC 0X03//Offset DAC 设置
define DIO 0X04//数字I/O 引脚设置
define DIR 0X05//输入输出的方向选择
define IOCON 0X06//I/O 配置寄存器
define OCC0 0X07//失调误差正系数
define OCC1 0X08//失调误差正系数
define OCC2 0X09//失调误差正系数
define GCC0 0X0A//增益误差校正系数
define GCC1 0X0B//增益误差校正系数
define GCC2 0X0C//增益误差校正系数
define DOR2 0X0D//模数转换数据高8位
define DOR1 0X0E//模数转换数据中8位
define DOR0 0X0F//模数转换数据低8位
//命令定义
define RDATA 0X01//从DOR 寄存器中读取数据
define RDATAC 0X03//从DOR 寄存器中连续读取数据
define STOPC 0X0F//停止从DOR 寄存器中连续读取数据
define RREG 0X10//低4位为寄存器地址
define WREG 0X50//低4位为寄存器地址
define CALSELF 0XF0//对芯片的失调误差和增益误差进行纠正
define OCALSELF 0XF1//对芯片的失调误差进行纠正
define GCALSELF 0XF2//对芯片的增益误差进行纠正
define OCALSYS 0XF3//对系统的失调误差进行纠正
define GCALSYS 0XF4//对系统的增益误差进行纠正
define WAKEUP 0XFB//将系统从睡眠模式模式中唤醒
define SYNC 0XFC//对DRDY 进行同步
define SLEEP 0XFD//使芯片进入睡眠模式
define RESET 0XFE//将芯片复位到上电后的状态
define P_ADD 0XA3//将芯片复位到上电后的状态
define SPI_SDI(n) (n?gpio_bit_set(GPIOA, GPIO_PIN_6):gpio_bit_reset(GPIOA, GPIO_PIN_6))
define SPI_SCK(n) (n?gpio_bit_set(GPIOA, GPIO_PIN_0):gpio_bit_reset(GPIOA, GPIO_PIN_0))
define SPI_SDO_READ() gpio_input_bit_get(GPIOA,GPIO_PIN_5)
define VOL_EXTI_LINE EXTI_4
define CURR_EXTI_LINE EXTI_5
unsigned long curr_adc,vol_adc;
void ADC_GPIO_init()
{
//IO口定义
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOC);
//SCK
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0);
//SDO
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_1);
//SDI
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
//CS_A
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7);
//CS_V
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7);
//DRDY2 电压
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
//DRDY1 电流
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_5);
/* connect EXTI line to GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN4);
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN5);
/* configure EXTI line */
exti_init(EXTI_4, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_4);
exti_init(EXTI_5, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_5);
}
/写一个字节的数据到CS1180的SDI引脚/
void Write_One_Byte(unsigned char Byte)
{
char i=0;
SPI_SCK(1);
for(;i<8;i++)
{
if(Byte&(0x80>>i)) //先传高位
{
SPI_SDI(1);
}
else
{
SPI_SDI(0);
}
Delay1us();
SPI_SCK(0); //写数据的时候,数据在上升沿被写入
Delay1us();
SPI_SCK(1);
Delay1us();
}
}
/从SDO引脚读取一个字节的数据/
unsigned char Read_One_Byte(void)
{
char i=0;
unsigned char Data = 0;
SPI_SCK(1);
for(;i<8;i++)
{ //读数据的时候,数据在下降沿被输出
SPI_SCK(0);
Delay1us();
Data = (Data << 1) | SPI_SDO_READ();
Delay1us();
SPI_SCK(1);
Delay1us();
}
return Data;
}
/1:读取ADC数据 命令编码:0x01/
unsigned long Read_Adc_Data(void)
{
//unsigned char datah,datam,datal;
unsigned long datah;
unsigned long datam,datal;
unsigned long c=0;
datal=datam=datah=0;
Write_One_Byte(0x01); //写入命令:0x01 写完后SCK=1
Delay1us();
datah=Read_One_Byte();
datam=Read_One_Byte();
datal=Read_One_Byte();
c=datah<<8|datam;
return(c);
}
if 0 //此段没有用到 暂未验证 感兴趣的可以加上尝试
/2:读取寄存器的值 命令编码:0001 rrrr xxxx nnnn/
/_void Read_Reg_Data(char start_reg_addr,char num,char_ptr)
{
Write_One_Byte(0x10|start_reg_addr); //命令的第一个字节
Write_One_Byte(num-1);
for(;num!=0;num--)
{
*(ptr++) = Read_One_Byte(); //将读取的寄存器的值顺序保存在数组中
}
}
*/
/3:写数据到控制寄存器中 命令编码:0101 rrrr xxxx nnnn/
unsigned char Write_Reg_Data(char start_reg_addr,char reg_data)
{
char err_num = 0;
Write_One_Byte(0x50|start_reg_addr); //命令的第一个字节,第一个寄存器为0x00
Write_One_Byte(0x00); //命令的第二个字节,总共写1个寄存器
Write_One_Byte(reg_data); //写入第一个寄存器值
return 0;
}
endif
//4:CS1180初始化函数
void CS1180_ADC_Init(void)
{
//初始化电流ADC
ADC_GPIO_init();
gpio_bit_reset(GPIOA, GPIO_PIN_7); //开电流片选 关电压
gpio_bit_set(GPIOC, GPIO_PIN_7);
Write_One_Byte(RESET);
Delay1us();
Write_Reg_Data(SETUP,0x00); // 128x PGA
Write_Reg_Data(ACR,0x62);
Write_Reg_Data(ODAC,0x30);
delay_ms(5);
while(DRDY1 == 1);
Read_One_Byte();
delay_ms(5);
gpio_bit_set(GPIOA, GPIO_PIN_7);
//初始化电压ADC
gpio_bit_set(GPIOC, GPIO_PIN_7);
gpio_bit_reset(GPIOA, GPIO_PIN_7);//关电流片选 开电压
Write_One_Byte(RESET);
Delay1us();
Write_Reg_Data(SETUP,0x00); // 128x PGA
Write_Reg_Data(ACR,0x62);
Write_Reg_Data(ODAC,0x30);
delay_ms(5);
while(DRDY2 == 1);
Read_One_Byte();
delay_ms(5);
delay_ms(5);
gpio_bit_set(GPIOC, GPIO_PIN_7);
//外部中断初始化
nvic_irq_enable(EXTI4_IRQn, 2U, 0U); //电压
nvic_irq_enable(EXTI5_9_IRQn, 1U, 0U); //电流
}
/外部中断0响应函数 读取电压/
void EXTI5_9_IRQHandler(void)
{
if (RESET != exti_interrupt_flag_get(VOL_EXTI_LINE)) {
nvic_irq_disable(EXTI5_9_IRQn);//关掉电流表中断
exti_interrupt_flag_clear(VOL_EXTI_LINE);
gpio_bit_reset(GPIOC, GPIO_PIN_7);
vol_adc = Read_Adc_Data() & 0xFFFFFF;
gpio_bit_set(GPIOC, GPIO_PIN_7);
}
nvic_irq_enable(EXTI5_9_IRQn, 1U, 0U);
}
/*中断开启需要先EA=1(总中断开)IT1=1;//下降沿触发
EX1=1;//开中断*/
/外部中断1响应函数 读取电流/
void EXTI4_IRQHandler(void)
{
if (RESET != exti_interrupt_flag_get(CURR_EXTI_LINE)) {
nvic_irq_disable(EXTI4_IRQn);//关掉电流表中断
exti_interrupt_flag_clear(CURR_EXTI_LINE);
gpio_bit_reset(GPIOA, GPIO_PIN_7);
curr_adc = Read_Adc_Data() & 0xFFFFFF;
gpio_bit_set(GPIOA, GPIO_PIN_7);
}
nvic_irq_enable(EXTI4_IRQn, 1U, 0U);
}