一、实现原理:
先将一个可以生成正弦波的数据表(table)保存在一片固定地址的内存中,然后在DAC以及这块内存中间使用DMA建立一个专属通道,使用定时器的TRGO触发模式触发DAC,DAC模块就可以定时地通过DAM通道拿取这片内存中的正弦波的数据,然后经过DAC数模转换,输出到引脚就可以得到一定频率、幅值的正弦波(波形)了。
二、实现方法(基于GD32):
1、定义正弦波数组
const unsigned short int sine_data[200] =
{ 2048,2308,2555,2773,2952,3083,3158,3179,3150,3075,2965,2830,2683,2535,2401,2286,2199,2144,2120,2128, 2157,2205,2264,2323,2378,2419,2440,2442,2424,2388,2337,2278,2214,2154,2104,2066,2046,2042,2055,2081, 2115,2153,2190,2218,2238,2242,2228,2199,2158,2105,2048,1990,1937,1896,1867,1853,1858,1877,1905,1942, 1980,2014,2040,2053,2049,2029,1991,1942,1881,1817,1758,1707,1671,1653,1655,1676,1717,1772,1831,1890, 1938,1968,1975,1951,1896,1809,1694,1560,1412,1265,1130,1020,945,916,937,1012,1143,1322,1540,1788, 2048,2308,2555,2773,2952,3083,3158,3179,3150,3075,2965,2830,2683,2535,2401,2286,2199,2144,2120,2128, 2157,2205,2264,2323,2378,2419,2440,2442,2424,2388,2337,2278,2214,2154,2104,2066,2046,2042,2055,2081, 2115,2153,2190,2218,2238,2242,2228,2199,2158,2105,2048,1990,1937,1896,1867,1853,1858,1877,1905,1942, 1980,2014,2040,2053,2049,2029,1991,1942,1881,1817,1758,1707,1671,1653,1655,1676,1717,1772,1831,1890, 1938,1968,1975,1951,1896,1809,1694,1560,1412,1265,1130,1020,945,916,937,1012,1143,1322,1540,1788
};
注意:全局变量已赋初值,单片机一上电后,会将此数据从ROM中拷贝到RAM中。
2、初始化各路时钟(GPIOA+DMA1+DAC+TIEMR5)
void rcu_config(void)
{
/* enable the clock of peripherals */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_DMA1);
rcu_periph_clock_enable(RCU_DAC);
rcu_periph_clock_enable(RCU_TIMER5);
}
3、GPIO初始化(模拟输入)
void gpio_config(void)
{
/* once enabled the DAC, the corresponding GPIO pin is connected to the DAC converter automatically */
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
}
4、 DMA配置
(使用DMA1的CH3通道)
#define DAC_DHR12R2_Address (0x40007414) // 如果使用DAC0(PA4)的话,地址为(0x40007408
)
void dma_config(void)
{
dma_parameter_struct dma_struct;
/* clear all the interrupt flags */
dma_flag_clear(DMA1, DMA_CH3, DMA_INTF_GIF);
dma_flag_clear(DMA1, DMA_CH3, DMA_INTF_FTFIF);
dma_flag_clear(DMA1, DMA_CH3, DMA_INTF_HTFIF);
dma_flag_clear(DMA1, DMA_CH3, DMA_INTF_ERRIF);
/* configure the DMA1 channel 2 */
dma_struct.periph_addr = DAC_DHR12R2_Address;
dma_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_struct.memory_addr = (uint32_t)(sine_data);
dma_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_struct.number = 200;
dma_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init(DMA1, DMA_CH3, &dma_struct);
dma_circulation_disable(DMA1, DMA_CH3); // 只触发一个数据组(200个),如果想持续触发,则enable即可
dma_channel_enable(DMA1, DMA_CH3);
}
5、DAC配置
(使用的是DAC1(对应PA5引脚))
void dac_config(void)
{
dac_deinit();
/* configure the DAC1 */
dac_trigger_source_config(DAC1, DAC_TRIGGER_T5_TRGO); // 使用定时器5的TRGO触发DAC
dac_trigger_enable(DAC1);
dac_wave_mode_config(DAC1, DAC_WAVE_DISABLE);
//dac_output_buffer_disable(DAC1);
dac_output_buffer_enable(DAC1);
/* enable DAC1 and DMA for DAC1 */
dac_enable(DAC1);
dac_dma_enable(DAC1);
}
6、定时器配置
(此处系统时钟为108MHz,设置定时器触发频率收到为50kHz,对应正弦波频率为50/200=0.25kHz)
/*!
\brief configure the TIMER5
\param[in] none
\param[out] none
\retval none
\ 20us ==> 50kHz ==> 108000000/2160 ==> (0xF+1)*(0x86+1)=2160
*/
void timer5_config(void)
{
/* configure the TIMER5 */
timer_prescaler_config(TIMER5, 0xF, TIMER_PSC_RELOAD_UPDATE);
timer_autoreload_value_config(TIMER5, 0x86);
timer_master_output_trigger_source_select(TIMER5, TIMER_TRI_OUT_SRC_UPDATE);
timer_enable(TIMER5);
}
总体实现流程: