首页 > 其他分享 >【RTT-Studio】详细使用教程七:SGM5352外部DAC使用

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

时间:2024-08-03 12:29:16浏览次数:22  
标签:rt SGM5352 DAC CLK RTT OUTPUT GPIO RCC define

文章目录

一、简介

本文主要介绍使用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.实验现象
通过控制台进行参数设置后,通道的输出情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标签:rt,SGM5352,DAC,CLK,RTT,OUTPUT,GPIO,RCC,define
From: https://blog.csdn.net/Hei_se_meng_yan/article/details/140875716

相关文章

  • fpc 3.3.1使用rtti
    生产不建议使用fpc3.3.1(Trunk)近日QQ群的SunGod和啊D等发现fpc3.3.1(Trunk)添加了和delphi一样的rtti功能,但fpc默认是没启用的。启用RTTI的条件:1、编译FPC时添加-dENABLE_DELPHI_RTTI2、在fpc.cfg最后一行添加-dENABLE_DELPHI_RTTI因编译fpc对我来说还是太麻烦,我喜欢用fpcudelu......
  • 【RTT-Studio】详细使用教程六:按键检测实现
    文章目录一、简介二、RTT时钟配置三、初始化配置四、完整代码五、测试验证一、简介本文主要介绍在RT-ThreadStudio中,如何对按键进行检测,分为两种方式进行检测:状态机方式:可以检测按键的单击、双击和长按,并且可以设置三个状态的检测时间长短,主要分为五个状态:未按、......
  • Win10 安装Bus Hound 后重启失败,启动修复 无法修复你的电脑 日志文件: E:\WINDOWS
    工作中用到了串口通讯,找到了BusHound,当安装完后提示重启,重启后直接启动失败。怀疑主要原因是安装了不支持Win10的BusHound版本,因为安装BusHound后会在系统中添加一个驱动: bhound7.sys,当Windows启动时加载bhound7.sys驱动失败导致Windows启动失败. 尝试了很多方法,包括进......
  • lazarus使用unidac+sqlite,用dbgrid显示float字段时遇到的问题
    遇到的问题:网友海使用过程发现,lazarus使用unidac+sqlite,用dbgrid显示float字段时遇到数据库的字段内容明明有多位小数,但在dbgrid只显示1位小数和截图最后1行显示1.1E2等问题。 在Navicat显示的表内容:这是他的解决方法: 修改UniConnection1的DataTypeMapping,将float映射为s......
  • 音视频入门基础:PCM专题(3)——使用Audacity工具分析PCM音频文件
     =================================================================音视频入门基础:PCM专题系列文章:音视频入门基础:PCM专题(1)——使用FFmpeg命令生成PCM音频文件并播放音视频入门基础:PCM专题(2)——使用Qt播放PCM音频文件音视频入门基础:PCM专题(3)——使用Audacity工具分析PC......
  • npm私服 verdaccio 搭建
    1、什么是npm私服我们前端(web,nodejs)平常使用的各种包,什么vue,react,react-router,zustand等,都会从https://registry.npmjs.org/这个镜像源上download,当然我们国内开发为了download方便,快速down下来,下载包的时候会指定国内镜像源,比如淘宝镜像。像这些提供给全网使用的镜像服......
  • 【RTT-Studio】详细使用教程四:PWM输出控制
    文章目录一、简介二、RTT时钟配置三、PWM初始化配置四、驱动代码编写五、测试验证一、简介本文将基于STM32F407VET6介绍,如何使用RT-ThreadStudio开发环境下使用输出PWM波形。主要是使用RTT自带的PWM设备进行编写的驱动函数,更加快捷便利。二、RTT时钟配置由于使......
  • 【STM32】RTT-Studio中HAL库开发教程四:DAC+DMA输出波形
    文章目录一、DAC介绍二、HAL库配置初始化三、RTT中初始化四、测试验证一、DAC介绍1.DAC作用DAC(Digital-to-AnalogConverter),即为数字/模拟转换模块,又称D/A转换器;作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与ADC相反。即为输出波形和输出固定电压......
  • WPF Behavior InvokeCommandAction Command CommandParameter
    //xaml<behavior:Interaction.Triggers><behavior:EventTriggerEventName="MouseWheel"SourceObject="{BindingElementName=img}"><behavior:InvokeCommandActionCommand="{BindingMouseWheelCmd}"......
  • 【STM32】RTT-Studio中HAL库开发教程二:RS485-DMA串行通信
    文章目录一、前期准备二、实验步骤1.使用STM32CubeMX配置初始化代码2.常用函数解析3.相关程序4.实验效果三、参考文章一、前期准备开发环境:基于RT-ThreadStudio软件的开发辅助软件:STM32CubeMX初始化代码生成调试软件:串口助手使用芯片:STM32F407VET6硬件环......