【RTT-Studio】详细使用教程七:SGM5352外部DAC使用

一、简介

本文主要介绍使用RTT-ThreadStudio来驱动SGM5352芯片的使用,该芯片主要是一个低功率,4通道,16位,电压输出DAC。它从2.7V到5.5V,设计保证了单调性。SGM5352-16通过使用外部参考电压来设置每个DAC通道的输出范围。它包含了一个电源复位电路,确保DAC输出功率到0V。SGM5352-16使用了一个3线串行SPI接口。
相关资料:
(1)芯片资料:SGM5352芯片手册
(2)参考电路:SGM5352参考电路设计

芯片使用:

  • SGM5352-16是一个16位电阻串DAC,理想输出电压可根据以下公式计算:Voutx = (Vrefh - Vrefl) * Din / 65535
  • 三线制串行接口(nSYNC、SCLK和DIN/OUT)兼容SPI接口标准。
  • 在正常操作中,启用销必须设置为较低。当启用销变高时,SGM5352-16对任何操作都没有响应。
    在这里插入图片描述

寄存器操作:
1.读取数据

二进制备注
0001 10000x18 —读取通道A数据
0001 10100x1A —读取通道B数据
0001 11000x1C —读取通道C数据
0001 11100x1D —读取通道D数据

2.指定操作

二进制备注
0001 00000x10 0x1234 —写通道A
0001 00100x12 0x3456 —写通道B
0001 01000x14 0x4567 —写通道C
0001 01100x16 0x6789 —写通道D
0001 00010x11 0x1234 —写通道A关闭
0001 00110x13 0x3456 —写通道B关闭
0001 01010x15 0x4567 —写通道C关闭
0001 01110x17 0x6789 —写通道D关闭

3.广播模式

二进制备注
0011 X0X0 X0x30 0x0000 同时使用每个通道临时寄存器中存储的数据更新系统中所有设备的所有通道。
0011 X1X0 data0x34 0x1234 写入所有设备并加载所有数据的dac。
0011 X1X1 0x00000x35 0x0000 写入所有设备,并在DB中使用关机命令加载所有DAC。详见表1。
0011 X0X1 0x80000x31 0x8000 启用SPI输出函数。
0011 X0X1 0x00000x31 0x0000 禁用SPI输出函数。

读写流程
1.先对CS、CLK和MOSI引脚进行初始化配置,以及初始电平设置。
2.写MOSI的模式切换函数,在接收数据的时候,需要进行MOSI引脚模式的切换。
3.编写寄存器读写函数
4.读写数据。写数据可以直接使用写寄存器函数即可,读数据时需要注意先使能SPI函数,再使用读寄存器函数。

PS:数据接收测试会有问题,如果哪位大佬有见解,可以分享一下!!!


二、RTT时钟配置

由于使用RTT生成的工程默认使用的是系统内部时钟,便于我们对时间的控制,所以通常会使用外部时钟,因此需要对工程中的时钟进行更改,更改内容如下:

  • 打开RT-Thread Studio软件新建基于芯片的项目,并使用外部时钟系统。
  • 在drv_clk.c文件中添加时钟配置函数,并且注释内部时钟的调用。
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /** Initializes the CPU, AHB and APB busses clocks
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 4;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB busses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
            | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
}

void clk_init(char *clk_source, int source_freq, int target_freq)
{
//    system_clock_config(target_freq);
    SystemClock_Config();
}

三、初始化配置

本文主要是使用SGM5352芯片输出三角波,以及控制其他通道数据不同的电平。
1.定时器初始化
先在board.h文件中将定时器打开,便于使用定时器进行数据的发送,如下:

/** if you want to use hardware timer you can use the following instructions.
 *
 * STEP 1, open hwtimer driver framework support in the RT-Thread Settings file
 *
 * STEP 2, define macro related to the hwtimer
 *                 such as     #define BSP_USING_TIM  and
 *                             #define BSP_USING_TIM1
 *
 * STEP 3, copy your hardwire timer init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file
 *                 such as     void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
 *
 * STEP 4, modify your stm32xxxx_hal_config.h file to support hardwere timer peripherals. define macro related to the peripherals
 *                 such as     #define HAL_TIM_MODULE_ENABLED
 *
 */

#define BSP_USING_TIM
#ifdef BSP_USING_TIM
#define BSP_USING_TIM3
#endif

在board.c中添加定时器的时钟初始化函数,基本函数如下:

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
    if (tim_baseHandle->Instance == TIM3)
    {
        /* Peripheral clock enable */
        __HAL_RCC_TIM3_CLK_ENABLE();
    }
}

在图形化界面中将定时器的驱动打开,如下:
在这里插入图片描述

如果定时器初始化函数没有定义,需要在drivers->include->config->tim_config.h中调价以下内容:

#ifdef BSP_USING_TIM3
#ifndef TIM3_CONFIG
#define TIM3_CONFIG                                         \
    {                                                       \
       .tim_handle.Instance     = TIM3,                     \
       .tim_irqn                = TIM3_IRQn,                \
       .name                    = "timer3",                 \
    }
#endif /* TIM3_CONFIG */
#endif /* BSP_USING_TIM3 */

2.SGM5352驱动代码
SGM5352写数据函数,总共需要发送数据24个字节的数据,可以分成两次发送:

/**
 * @brief SGM5352写数据
 * @param config  :写地址
 * @param DAC_DATA:写入的数据
 */
void SGM5352_WHITE(uint8_t config, uint16_t DAC_DATA)
{
    SPI_GPIO_Mode_Change(GPIO_MODE_OUTPUT_PP);

    CLK_OUTPUT_HIGH;
    CS_OUTPUT_HIGH;

    CS_OUTPUT_LOW;

    for (uint8_t i = 0; i < 8; ++i)
    {
        if (config & (1 << (7 - i)))
        {
            MOSI_OUTPUT_HIGH;
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;
        CLK_OUTPUT_HIGH;
    }

    for (int i = 0; i < 16; ++i)
    {
        if (DAC_DATA & (1 << (15 - i)))
        {
            MOSI_OUTPUT_HIGH
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;
        CLK_OUTPUT_HIGH;
    }

    CS_OUTPUT_HIGH;
}

SGM5352读数据函数,在使用的时候需要提前打开SPI输出函数使能,并且该函数在发送完前8个字节数据后,需要更改模式为输入模式,从未接收芯片返回的数据。

/**
 * @brief SGM5352读数据
 * @param config:读取的地址
 * @return 返回读取到的数据
 */
uint16_t SGM5352_READ(uint8_t config)
{
    uint16_t data = 0;

    SPI_GPIO_Mode_Change(GPIO_MODE_OUTPUT_PP);

    CLK_OUTPUT_HIGH;
    CS_OUTPUT_HIGH;

    CS_OUTPUT_LOW;

    for (int i = 0; i < 8; ++i)
    {
        if (config & (1 << (7 - i)))
        {
            MOSI_OUTPUT_HIGH;
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;

        CLK_OUTPUT_HIGH;
    }

    SPI_GPIO_Mode_Change(GPIO_MODE_INPUT);

    for (int i = 0; i < 16; ++i)
    {
        CLK_OUTPUT_LOW;
        data = (data << 1) | MOSI_INPUT;
        CLK_OUTPUT_HIGH;
    }

    CS_OUTPUT_HIGH;

    return data;
}

3.定时发送数据
输出三角波时,需要通过定时器进行数据的实时更新,并且需要更新三角波的缓冲区。时钟计算:f = 1 / ((40*100)/1000000) ==> t = 1000000 / (100 * f):其中1000000是计数频率,f是频率,100是采样点的个数。

/**
 * @brief 三角波信号缓存填充
 */
void Signal_Ramp(float value)
{
    uint16_t dac = value * 65535 / 2.5;

    for (int i = 0; i < 50; i++)
    {
        signalRampBuffer[i] = i * dac / 50;
    }

    for (int i = 50; i < 100; i++)
    {
        signalRampBuffer[i] = (100 - i) * dac / (100 - 50);
    }
}

/**
 * @brief 定时器超时回调函数
 * @param dev
 * @param size
 * @return
 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(dac_sem);

    return 0;
}

/**
 * @brief 启动定时器,设置定时时间
 * @param fre:设置频率
 */
int start_Hwtimer(uint16_t fre)
{
    rt_err_t ret = RT_EOK;
    rt_hwtimer_mode_t mode;     /* 定时器模式 */
    rt_uint32_t freq = 1000000; /* 计数频率 */

    if (dev_state == 0)
    {
        dev_state = 1;

        /* 查找定时器设备 */
        hw_dev = rt_device_find(HWTIMER_DEV_NAME);
        RT_ASSERT(hw_dev != RT_NULL);

        /* 以读写方式打开设备 */
        ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
        RT_ASSERT(ret == RT_EOK);

        /* 设置超时回调函数 */
        rt_device_set_rx_indicate(hw_dev, timeout_cb);

        /* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
        rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);

        /* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
        mode = HWTIMER_MODE_PERIOD;
        ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
        RT_ASSERT(ret == RT_EOK);
    }

    /* 设置定时器超时值,并启动定时器 */
    rt_hwtimerval_t timeout_s;
    // f = 1 / ((40*100)/1000000) ==> t = 1000000 / (100 * f)
    timeout_s.sec = 0;
    timeout_s.usec = 1000000 / (100 * fre);
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
    }

    return 0;
}

/**
 * @brief 关闭定时器
 */
void close_Hwtimer(void)
{
    dev_state = 0;
    rt_device_close(hw_dev);
    SGM5352_WHITE(ADDR_CHANNELA_CLOSE, 0);
}

四、完整代码

1.sgm5352.c :可以使用控制台来控制每个通道的输出DAC值,并且可以更改三角波的频率和输出电压:

#include "sgm5352.h"

/**
 * @brief SEG5352的GPIO引脚初始化
 */
void SEG5352_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    /*Configure GPIO pin : CS_Pin */
    GPIO_InitStruct.Pin = CS_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct);

    /*Configure GPIO pins : CLK_Pin MOSI_Pin */
    GPIO_InitStruct.Pin = CLK_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(CLK_GPIO_Port, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MOSI_GPIO_Port, &GPIO_InitStruct);

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(CLK_GPIO_Port,  CLK_Pin,  GPIO_PIN_RESET);
    HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);

    dac_sem = rt_sem_create("dac_sem", 0, RT_IPC_FLAG_PRIO);
}

/**
 * @brief SPI引脚模式切换
 * @param Mode:GPIO_MODE_OUTPUT_PP、GPIO_MODE_INPUT
 */
void SPI_GPIO_Mode_Change(uint32_t Mode)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    /*Configure GPIO pins : CLK_Pin MOSI_Pin */
    GPIO_InitStruct.Pin = MOSI_Pin;
    GPIO_InitStruct.Mode = Mode;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
 * @brief SGM5352写数据
 * @param config  :写地址
 * @param DAC_DATA:写入的数据
 */
void SGM5352_WHITE(uint8_t config, uint16_t DAC_DATA)
{
    SPI_GPIO_Mode_Change(GPIO_MODE_OUTPUT_PP);

    CLK_OUTPUT_HIGH;
    CS_OUTPUT_HIGH;

    CS_OUTPUT_LOW;

    for (uint8_t i = 0; i < 8; ++i)
    {
        if (config & (1 << (7 - i)))
        {
            MOSI_OUTPUT_HIGH;
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;
        CLK_OUTPUT_HIGH;
    }

    for (int i = 0; i < 16; ++i)
    {
        if (DAC_DATA & (1 << (15 - i)))
        {
            MOSI_OUTPUT_HIGH
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;
        CLK_OUTPUT_HIGH;
    }

    CS_OUTPUT_HIGH;
}

/**
 * @brief SGM5352读数据
 * @param config:读取的地址
 * @return 返回读取到的数据
 */
uint16_t SGM5352_READ(uint8_t config)
{
    uint16_t data = 0;

    SPI_GPIO_Mode_Change(GPIO_MODE_OUTPUT_PP);

    CLK_OUTPUT_HIGH;
    CS_OUTPUT_HIGH;

    CS_OUTPUT_LOW;

    for (int i = 0; i < 8; ++i)
    {
        if (config & (1 << (7 - i)))
        {
            MOSI_OUTPUT_HIGH;
        }
        else
        {
            MOSI_OUTPUT_LOW;
        }

        CLK_OUTPUT_LOW;

        CLK_OUTPUT_HIGH;
    }

    SPI_GPIO_Mode_Change(GPIO_MODE_INPUT);

    for (int i = 0; i < 16; ++i)
    {
        CLK_OUTPUT_LOW;
        data = (data << 1) | MOSI_INPUT;
        CLK_OUTPUT_HIGH;
    }

    CS_OUTPUT_HIGH;

    return data;
}

/**
 * @brief 三角波信号缓存填充
 */
void Signal_Ramp(float value)
{
    uint16_t dac = value * 65535 / 2.5;

    for (int i = 0; i < 50; i++)
    {
        signalRampBuffer[i] = i * dac / 50;
    }

    for (int i = 50; i < 100; i++)
    {
        signalRampBuffer[i] = (100 - i) * dac / (100 - 50);
    }
}

/**
 * @brief 定时器超时回调函数
 * @param dev
 * @param size
 * @return
 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(dac_sem);

    return 0;
}

/**
 * @brief 启动定时器,设置定时时间
 * @param fre:设置频率
 */
int start_Hwtimer(uint16_t fre)
{
    rt_err_t ret = RT_EOK;
    rt_hwtimer_mode_t mode;     /* 定时器模式 */
    rt_uint32_t freq = 1000000; /* 计数频率 */

    if (dev_state == 0)
    {
        dev_state = 1;

        /* 查找定时器设备 */
        hw_dev = rt_device_find(HWTIMER_DEV_NAME);
        RT_ASSERT(hw_dev != RT_NULL);

        /* 以读写方式打开设备 */
        ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
        RT_ASSERT(ret == RT_EOK);

        /* 设置超时回调函数 */
        rt_device_set_rx_indicate(hw_dev, timeout_cb);

        /* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
        rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);

        /* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
        mode = HWTIMER_MODE_PERIOD;
        ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
        RT_ASSERT(ret == RT_EOK);
    }

    /* 设置定时器超时值,并启动定时器 */
    rt_hwtimerval_t timeout_s;
    // f = 1 / ((40*100)/1000000) ==> t = 1000000 / (100 * f)
    timeout_s.sec = 0;
    timeout_s.usec = 1000000 / (100 * fre);
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
    }

    return 0;
}

/**
 * @brief 关闭定时器
 */
void close_Hwtimer(void)
{
    dev_state = 0;
    rt_device_close(hw_dev);
    SGM5352_WHITE(ADDR_CHANNELA_CLOSE, 0);
}

/**
 * @brief 设置三角波数据
 * @param argc
 * @param argv
 */
void Set_Signal_Ramp_Param(int argc, char **argv)
{
    RT_ASSERT(argc == 3 || argc == 2);
    if (strcmp(argv[0], "signal") == 0)
    {
        if (strcmp(argv[1], "vol") == 0)
        {
            Signal_Ramp(atof(argv[2]));
        }
        else if (strcmp(argv[1], "fre") == 0)
        {
            start_Hwtimer(atoi(argv[2]));
        }
        else if (strcmp(argv[1], "stop") == 0)
        {
            close_Hwtimer();
        }
    }
}
MSH_CMD_EXPORT_ALIAS(Set_Signal_Ramp_Param, signal, Set Signal Ramp Param);

/**
 * @brief 设置其他三个通道参数
 * @param argc
 * @param argv
 */
void Set_Channel_Param(int argc, char **argv)
{
    RT_ASSERT(argc == 3 || argc == 2);

    uint16_t dac = atof(argv[2]) * 65535 / 2.5;
    if (strcmp(argv[0], "set") == 0)
    {
        if (strcmp(argv[1], "B") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELB_W, dac);
        }
        else if (strcmp(argv[1], "C") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELC_W, dac);
        }
        else if (strcmp(argv[1], "D") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELD_W, dac);
        }
        else if (strcmp(argv[1], "stop_B") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELB_CLOSE, 0);
        }
        else if (strcmp(argv[1], "stop_C") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELC_CLOSE, 0);
        }
        else if (strcmp(argv[1], "stop_D") == 0)
        {
            SGM5352_WHITE(ADDR_CHANNELD_CLOSE, 0);
        }
    }
}
MSH_CMD_EXPORT_ALIAS(Set_Channel_Param, set, Set Channel Param);

2.sgm5352.h

#ifndef APPLICATIONS_SGM5352_H_
#define APPLICATIONS_SGM5352_H_

#include <drv_common.h>
#include <string.h>
#include <stdlib.h>

/**====================================================###### 宏定义 ######==================================================*/
#define BOARD_CAST_MODE     0x34            // 广播模式地址

#define ADDR_CHANNELA_W     0x10            // 写通道A地址
#define ADDR_CHANNELB_W     0x12            // 写通道B地址
#define ADDR_CHANNELC_W     0x14            // 写通道C地址
#define ADDR_CHANNELD_W     0x16            // 写通道D地址

#define ADDR_CHANNELA_R     0x18            // 读取通道A数据
#define ADDR_CHANNELB_R     0x1A            // 读取通道B数据
#define ADDR_CHANNELC_R     0x1C            // 读取通道C数据
#define ADDR_CHANNELD_R     0x1D            // 读取通道D数据

#define ADDR_CHANNELA_CLOSE 0x11            // 写通道A关闭
#define ADDR_CHANNELB_CLOSE 0x13            // 写通道A关闭
#define ADDR_CHANNELC_CLOSE 0x15            // 写通道A关闭
#define ADDR_CHANNELD_CLOSE 0x17            // 写通道A关闭

#define SPI_OUTPUT          0x31            // 启用SPI输出函数
#define SPI_OUTPUT_ENABLE   0x8000          // 启用SPI发送数据位
#define SPI_OUTPUT_UNENABLE 0x0000          // 禁用SPI发送数据位

#define CS_Pin              GPIO_PIN_6      // 片选引脚
#define CS_GPIO_Port        GPIOF
#define CLK_Pin             GPIO_PIN_10     // 时钟引脚
#define CLK_GPIO_Port       GPIOB
#define MOSI_Pin            GPIO_PIN_2      // 主输出从输入
#define MOSI_GPIO_Port      GPIOC

#define CS_OUTPUT_HIGH      HAL_GPIO_WritePin(CS_GPIO_Port,   CS_Pin,   GPIO_PIN_SET);
#define CS_OUTPUT_LOW       HAL_GPIO_WritePin(CS_GPIO_Port,   CS_Pin,   GPIO_PIN_RESET);
#define CLK_OUTPUT_HIGH     HAL_GPIO_WritePin(CLK_GPIO_Port,  CLK_Pin,  GPIO_PIN_SET);
#define CLK_OUTPUT_LOW      HAL_GPIO_WritePin(CLK_GPIO_Port,  CLK_Pin,  GPIO_PIN_RESET);
#define MOSI_OUTPUT_HIGH    HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET);
#define MOSI_OUTPUT_LOW     HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET);

#define MOSI_INPUT          HAL_GPIO_ReadPin(MOSI_GPIO_Port, MOSI_Pin);

#define HWTIMER_DEV_NAME   "timer3"         // 定时器名称
TIM_HandleTypeDef htim3;

uint16_t signalRampBuffer[100];             // 三角波数据缓冲区
rt_device_t hw_dev;                         // 定时器设备句柄
rt_uint8_t dac_index;                       // DAC序号
rt_uint8_t dev_state;                       // 设备状态
rt_sem_t dac_sem;                           // dac发送信号量
/**====================================================#######  END  #######=================================================*/

/**=================================================##### 函数及变量声明 #####===============================================*/
extern void SEG5352_GPIO_Init(void);
extern void SGM5352_WHITE(uint8_t config, uint16_t DAC_DATA);
extern uint16_t SGM5352_READ(uint8_t config);
extern void Signal_Ramp(float value);
extern void Hwtimer_Init(void);
extern int start_Hwtimer(uint16_t fre);
/**====================================================#######  END  #######=================================================*/

#endif /* APPLICATIONS_SGM5352_H_ */

3.main.c

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "sgm5352.h"

int main(void)
{
    int count = 1;

    SEG5352_GPIO_Init();

    while (count)
    {
        rt_err_t result = rt_sem_take(dac_sem, RT_WAITING_FOREVER);
        if (result == RT_EOK)
        {
            SGM5352_WHITE(ADDR_CHANNELA_W, signalRampBuffer[dac_index++]);
            if (dac_index >= 100) dac_index = 0;
        }
    }

    return RT_EOK;
}

五、测试验证

1.通过控制台来进行数据的设置、控制输出:指令分别如下

指令功能
signal vol 2设置三角波电压2V
signal fre 40设置三角波频率40Hz
signal stop关闭三角波输出
set B 1设置通道B电压为1V
set C 2设置通道C电压为2V
set D 2.5设置通道D电压为2.5V
set stop_B关闭通道B输出
set stop_C关闭通道C输出
set stop_D关闭通道D输出

2.实验现象
通过控制台进行参数设置后,通道的输出情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值