硬汉嵌入式论坛

 找回密码
 立即注册
查看: 470|回复: 9
收起左侧

[ADC] AD7606B采集正弦波

[复制链接]

1

主题

7

回帖

10

积分

新手上路

积分
10
发表于 2025-12-5 12:36:30 | 显示全部楼层 |阅读模式
初学者,用STM32H7+AD7606B采集1HZ正弦波,没有用定时器和中断,单纯GPIO口控制引脚,为什么会出现图中状况,麻烦各位大佬看一下是什么原因,谢谢!




/* 系统时钟频率 */
#define SYS_FREQ  480000000UL
#define CYCLES_PER_US  (SYS_FREQ / 1000000UL)  // 480

/* 确保DWT已启用 */
static inline void DWT_Init(void)
{
    if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
        DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    }
}

/* 基于DWT的精确延时(纳秒级)*/
static inline void AD7606B_Delay_ns(uint32_t ns)
{
    if (ns < 10) return;  // 小于10ns不延时
   
    uint32_t cycles = (ns * CYCLES_PER_US + 999) / 1000;
    uint32_t start = DWT->CYCCNT;
   
    while ((DWT->CYCCNT - start) < cycles);
}

/* 基于DWT的微秒延时 */
static inline void AD7606B_Delay_us(uint32_t us)
{
    uint32_t cycles = us * CYCLES_PER_US;
    uint32_t start = DWT->CYCCNT;
   
    while ((DWT->CYCCNT - start) < cycles);
}

void AD7606B_Init(void)
{
            /* 初始化DWT(如果尚未初始化) */
    DWT_Init();
       
    /* 模式配置 */
    AD7606B_SER_L;      // 并行模式
    AD7606B_STBY_H;     // 退出待机模式,进入工作模式
   
    /* 控制引脚初始状态 */
    AD7606B_RD_H;       // RD初始高电平
    AD7606B_CS_H;       // CS初始高电平(禁用芯片)
   
    /* 过采样设置 - 无过采样(最高速率) */
    AD7606B_OS0_L;      // OS[2:0] = 000
    AD7606B_OS1_L;      // 无过采样,200kSPS每通道
    AD7606B_OS2_L;      // 或800kSPS总吞吐量
   
//    /* 硬件稳定时间 */
//    HAL_Delay(1);      // 使用HAL延时更可靠
       
            /* 硬件稳定时间 */
    AD7606B_Delay_us(1000);  // 1ms延时,使用DWT
}

void AD7606B_Reset(void)
{
    /* 根据数据手册:完全复位需要3μs高电平脉冲 */
    AD7606B_RESET_L;
    AD7606B_Delay_ns(100);      // 100ns低电平
    AD7606B_RESET_H;
//    AD7606B_Delay_ns(3000);
    AD7606B_Delay_us(3);      // 3μs高电平脉冲        //
    AD7606B_RESET_L;
   
//    /* 复位后设备建立时间(50ns) */
//    HAL_Delay(1);  // 1ms,远大于253μs,确保稳定
       
            /* 复位后设备建立时间(根据数据手册至少253μs) */
    AD7606B_Delay_us(254);    // 稍微大于最小值确保稳定
}

void AD7606B_Start(void)
{
    /* CONVST脉冲:低电平至少10ns,高电平至少10ns */
    AD7606B_CONVST_L;
    AD7606B_Delay_ns(20);        // 20ns低电平(大于最小值10ns)
    AD7606B_CONVST_H;
    AD7606B_Delay_ns(20);       // 20ns高电平
    // 注意:连续CONVST上升沿之间至少1.25μs
}

/* 获取单通道16位数据 */
static uint16_t AD7606B_Get_PinData(void)
{
    uint16_t result = 0;
   
    /* 读取16个数据引脚 */
    for (uint8_t i = 0; i < 16; i++)
                {
        if (HAL_GPIO_ReadPin(data_pins.port, data_pins.pin) == GPIO_PIN_SET)
                                {
            result |= (1 << i);
        }
    }
   
    return result;
}

void AD7606B_Get_Data(uint16_t *data)
{
    uint32_t timeout = 1000000;  // 超时计数器
   
    /* 等待BUSY变低(转换完成) */
    while (AD7606B_BUSY == GPIO_PIN_SET)
                {
        if (--timeout == 0) {
            /* 超时处理 */
            return;
        }
    }
   
    /* 使能芯片 */
    AD7606B_CS_L;
    AD7606B_Delay_ns(5);  // CS下降沿到RD下降沿建立时间
   
    for (uint8_t i = 0; i < AD7606B_CHANNEL_MAX; i++)
                {
        /* RD脉冲:低电平至少10ns,高电平至少10ns */
        AD7606B_RD_L;
        AD7606B_Delay_ns(15);  // 15ns低电平(大于最小值10ns)
        
        AD7606B_RD_H;
        AD7606B_Delay_ns(15);  // 数据建立时间(RD上升沿后数据至少保持12ns)
        
        /* 读取数据 - 在RD高电平期间读取 */
        data = AD7606B_Get_PinData();
                       
                          /* RD周期时间:至少30ns(V_DRIVE>2.7V时) */
        if (i < AD7606B_CHANNEL_MAX - 1)
        {
            AD7606B_Delay_ns(30);  // 确保RD周期时间
        }
                               
                        }

    /* 禁用芯片 */  
    AD7606B_Delay_ns(5);  // RD上升沿到CS上升沿保持时间(最小值0ns)                       
    AD7606B_CS_H;
}

static double AD7606B_Range_Digital2Voltage(uint16_t data, uint8_t range)
{
    int16_t signed_data = (int16_t)data;  
   
    switch (range) {
        case Range_2_5_V:
            return signed_data * 5.0 / 65536.0;
        case Range_5_V:
            return signed_data * 10.0 / 65536.0;
        case Range_10_V:
            return signed_data * 20.0 / 65536.0;
        default:
            return 0;
    }
}

void AD7606B_Get_Voltage(uint16_t *data, double *voltage_data, uint8_t range)
{
    for (uint8_t i = 0; i < AD7606B_CHANNEL_MAX; i++)
          {
        voltage_data = AD7606B_Range_Digital2Voltage(data, range);
    }
}

/* 完整的单次采集流程 */
void AD7606B_Single_Acquisition(double *voltage_data, uint8_t range)
{
    uint16_t raw_data[AD7606B_CHANNEL_MAX];
   
    /* 1. 启动转换 */
    AD7606B_Start();
   
    /* 2. 等待并读取数据 */
    AD7606B_Get_Data(raw_data);
   
    /* 3. 转换为电压 */
    AD7606B_Get_Voltage(raw_data, voltage_data, range);
}




int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

        ADSerial_Init();
        AD7606B_Init();
        AD7606B_Reset();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
               
                AD7606B_Single_Acquisition(AD7606B_Voltage, Range_10_V);
                printf("%.3f\r\n", AD7606B_Voltage[0]);

//                HAL_Delay(1);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}





bccf242109d45ea22d0bf4b01d32061d.png
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120448
QQ
发表于 2025-12-5 14:31:53 | 显示全部楼层
从效果来看,采集失败的地方好像都是同一个值(或者附近值)

应该是你的时序实现还有问题,推荐用硬件SPI或者FMC实现。
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
 楼主| 发表于 2025-12-5 16:05:35 | 显示全部楼层
eric2013 发表于 2025-12-5 14:31
从效果来看,采集失败的地方好像都是同一个值(或者附近值)

应该是你的时序实现还有问题,推荐用硬件SP ...

谢谢!那我去学学
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
 楼主| 发表于 2025-12-9 18:01:21 | 显示全部楼层
eric2013 发表于 2025-12-5 14:31
从效果来看,采集失败的地方好像都是同一个值(或者附近值)

应该是你的时序实现还有问题,推荐用硬件SP ...

您好,我想问一下,我改用FMC读取数据,没有用FIFO,直接读取发现还是上述的问题,那可能会是杜邦线连接或者是板子的问题么
fd1778f5b870154b4b9e21858cd0a6da.png
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
 楼主| 发表于 2025-12-9 18:41:09 | 显示全部楼层
eric2013 发表于 2025-12-5 14:31
从效果来看,采集失败的地方好像都是同一个值(或者附近值)

应该是你的时序实现还有问题,推荐用硬件SP ...

您好,我想问一下,我试了下,我串行没这个问题,那可能是并行杜邦线连线的问题是么
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120448
QQ
发表于 2025-12-10 10:52:03 | 显示全部楼层
Wulele 发表于 2025-12-9 18:41
您好,我想问一下,我试了下,我串行没这个问题,那可能是并行杜邦线连线的问题是么

有可能,也有可能是并行的时序有点问题。
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
 楼主| 发表于 2025-12-11 11:43:34 | 显示全部楼层
eric2013 发表于 2025-12-10 10:52
有可能,也有可能是并行的时序有点问题。

您好,我昨天考虑是不是其他通道干扰的问题,把其他通道接地,发现1.9附近的干扰消失,但变成0点。所以可以确定这接线的问题么,还是说可能还是时序有问题。
回复

使用道具 举报

15

主题

59

回帖

104

积分

初级会员

积分
104
发表于 2025-12-11 14:20:24 | 显示全部楼层
Wulele 发表于 2025-12-11 11:43
您好,我昨天考虑是不是其他通道干扰的问题,把其他通道接地,发现1.9附近的干扰消失,但变成0点。所以可 ...

不存在通道间的干扰,接线的问题,我之间也有过,线接触不良啥的
回复

使用道具 举报

1

主题

7

回帖

10

积分

新手上路

积分
10
 楼主| 发表于 2025-12-11 17:02:25 | 显示全部楼层
海米阿门 发表于 2025-12-11 14:20
不存在通道间的干扰,接线的问题,我之间也有过,线接触不良啥的

有什么好的解决方法么,还是说只能设计转接板了
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120448
QQ
发表于 2025-12-12 11:03:30 | 显示全部楼层
Wulele 发表于 2025-12-11 17:02
有什么好的解决方法么,还是说只能设计转接板了

最好实际接到板子上测试。并口最好别飞线。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-1-10 17:23 , Processed in 0.064598 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表