#include "cs1238.h"
#define DOUT_GPIO_PIN GPIO_Pin_0 ///< cs1238 数据脚
#define SCLK_GPIO_PIN GPIO_Pin_1 ///< 模拟时钟脚
/* 时钟脚 输出模式下 高低控制 */
#define IO_CLK_AD_H() GPIO_SetBits(GPIOC,SCLK_GPIO_PIN)
#define IO_CLK_AD_L() GPIO_ResetBits(GPIOC,SCLK_GPIO_PIN)
/* 数据脚 输出模式下 高低控制 */
#define IO_DATA_AD_H() GPIO_SetBits(GPIOC,DOUT_GPIO_PIN)
#define IO_DATA_AD_L() GPIO_ResetBits(GPIOC,DOUT_GPIO_PIN)
/* 数据脚 输入模式下 读取的数值 */
#define GET_IO_AD_DATA GPIO_ReadInputDataBit(GPIOC,DOUT_GPIO_PIN)
/**
* @brief 设置时钟引脚为输出模式
*
*/
void set_sclk_mode_out(void)
{
GPIO_Init(GPIOC,SCLK_GPIO_PIN,GPIO_Mode_Out_OD_Low_Fast);
}
/**
* @brief 设置数据工作引脚模式为 输入上拉
*
*/
void set_dout_mode_in(void)
{
GPIO_Init(GPIOC,DOUT_GPIO_PIN, GPIO_Mode_In_PU_No_IT);
}
/**
* @brief 设置数据工作引脚模式为 输出模式
*
*/
void set_dout_mode_out(void)
{
GPIO_Init(GPIOC,DOUT_GPIO_PIN, GPIO_Mode_Out_OD_Low_Fast);
}
/**
* @brief 通信时序 SCL 电平延时时间
* 需要<100μs, 否则会误触发进入休眠模式, 一般建议 SCL=2μs~15μs
*/
void Delay_us(uint8_t nCount)
{
while (nCount != 0)
{
nCount--;
}
}
void sclk_delay(void)
{
Delay_us(3);
}
/**
* @brief cs1238 时序时钟
*
*/
void cs1238_clock(void)
{
IO_CLK_AD_H();
sclk_delay();
IO_CLK_AD_L();
sclk_delay();
}
/**
* @brief 读取CS1238的AD数据
*
* @return int32_t
*/
int32_t read_cs1238_ad_data(void)
{
static uint16_t bit_cout = 0;
static int32_t data_temp = 0;
while (GET_IO_AD_DATA) //等待芯片准备好
{
//定时查询的方法需要缩短查询间隔 例如:1ms~5ms
bit_cout++;
if (bit_cout > 4000)
{
bit_cout = 0;
return 0;
// 超时退出
}
}
/* 1: clk1 ~ clk24 ADC数据*/
data_temp = 0;
for (bit_cout = 0; bit_cout < 24; bit_cout++)
{
data_temp <<= 1; //左移1位准备接受数据 初始默认0
cs1238_clock();
if (GET_IO_AD_DATA) //有数值则累加
{
data_temp++;
}
}
/* 2 ~ 7: clk25 ~ clk45 完整时序为 46 个 clocks 为读写寄存器*/
for (bit_cout = 0; bit_cout < 21; bit_cout++)
{
cs1238_clock(); //给一周期时钟
}
/* 8: clk46 */
set_dout_mode_out(); //第46个SCLK 输出 拉高
IO_DATA_AD_H();
cs1238_clock();
set_dout_mode_in();
IO_CLK_AD_L();
if (data_temp & 0x00800000) // 判断是负数 最高位24位是符号位
{
return -(((~data_temp) & 0x007FFFFF) + 1); // 补码变源码
}
return data_temp; // 正数的补码就是源码
}
/**
* @brief 设置CS1238寄存器
*
* @param[in] ad_reg 0x00 通道 A | PGA 1倍 | 速率 10 | REF 开启 | 保留位 0
* 0x01 通道 B | PGA 1倍 | 速率 10 | REF 开启 | 保留位 0
*/
int set_cs1238_config(uint8_t ad_reg)
{
static uint16_t bit_cout = 0;
static uint8_t reg_temp = 0x00;
//DOUT由高变低之后开始读取数据
set_dout_mode_out();
IO_DATA_AD_H();
set_dout_mode_in();
IO_CLK_AD_L(); //时钟拉低
while (GET_IO_AD_DATA) //等待芯片准备好
{
//定时查询的方法需要缩短查询间隔 例如:1ms~5ms
bit_cout++;
if (bit_cout > 4000)
{
bit_cout = 0;
return -1; // 超时退出
}
}
/* 1 ~ 4: clk1-clk29 */
for (bit_cout = 0; bit_cout < 29; bit_cout++)
{
cs1238_clock(); //给一周期时钟
}
/* 5: clk30 - clk36 发送写命令字 */
set_dout_mode_out();
reg_temp = 0xCA; //命令长度为 7bits (写0x65)左移1位
for (bit_cout = 0; bit_cout < 7; bit_cout++)
{
if (reg_temp & 0x80) //MSB
{
IO_DATA_AD_H();
}
else
{
IO_DATA_AD_L();
}
reg_temp = reg_temp << 1;
cs1238_clock();
}
/* 6: clk37 */
cs1238_clock();
/* 7: clk38 ~ clk45 写入寄存器值 */
reg_temp = ad_reg;
for (bit_cout = 0; bit_cout < 8; bit_cout++)
{
if (reg_temp & 0x80) //MSB
{
IO_DATA_AD_H();
}
else
{
IO_DATA_AD_L();
}
reg_temp = reg_temp << 1;
cs1238_clock();
}
/* 8: clk46 */
IO_DATA_AD_H();
cs1238_clock();
return 0;
}
/**
* @brief 初始化cs1238
*
*/
void cs1238_init(void)
{
// 设置 cs1238时钟引脚为 输出
set_sclk_mode_out();
// 设置 cs1238数据脚 输出 拉高
set_dout_mode_out();
}
/**
* @brief 顺序读取CS1238 通道A 通道B ADC数值
*
* @param[in] adc1_data
* @param[in] adc2_data
*/
void read_cs1238_all_ad_data(cs1238_load_info_t* cs1238_info)
{
// 读通道A数值
set_cs1238_config(0x00);
cs1238_info->adc1_data = read_cs1238_ad_data();
sclk_delay();
// 读通道2数值
set_cs1238_config(0x02);
cs1238_info->adc2_data = read_cs1238_ad_data();
sclk_delay();
}