IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> M-Arch(6)第五个示例:DAC -> 正文阅读

[嵌入式]M-Arch(6)第五个示例:DAC

前言

回顾下之前的章节:

  • 第一章节中我们描述了整个框架的核心设计思路以及主要的文件架构

  • 第二章节中我们基于一个简单的定时器OS实现了串口的数据打印,并完成了通用crc模块的设计和测试

  • 第三章节中我们给出了真随机数和伪随机数的概念和代码示例,并在架构上对接口进行了重构

  • 第四章节中我们回顾了FMC的基本知识,并给出了示例,后面我们将在设计IAP的时候再次使用到FMC

  • 第五章节中我们使用ADC和DMA搭建了一个通用的采样框架,并通过串口给出了采样的数据示例

本文我们将总结下DAC的基本使用方法,并通过DAC生成任意频率的正弦波,三角波和方波。

什么是DAC?

前面我们讲过了ADC是把模拟量转成数字量,那么DAC就是反过来,即把数字量转成模拟量。

DAC一般需要配置的内容包括:

  1. IO配置(时钟,模拟输入)

  2. DAC参数配置(触发源,附加噪声?,数据宽度)

  3. 中断和DMA(使能)配置

DAC的配置比较简单,直接给出代码:

STM32

void?dac1_init(void)
{
????DAC_InitTypeDef?DAC_InitStructure;
????GPIO_InitTypeDef??GPIO_InitStructure;
????
????RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,?ENABLE);
????RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,?ENABLE);

????GPIO_InitStructure.GPIO_Pin?=?GPIO_Pin_4;
????GPIO_InitStructure.GPIO_Mode?=?GPIO_Mode_AIN;
????GPIO_Init(GPIOA,?&GPIO_InitStructure);

????DAC_DeInit();

????DAC_StructInit(&DAC_InitStructure);
????DAC_InitStructure.DAC_Trigger?=?DAC_Trigger_Software;
????DAC_InitStructure.DAC_WaveGeneration?=?DAC_WaveGeneration_None;
????DAC_InitStructure.DAC_OutputBuffer?=?ENABLE;
????DAC_Init(DAC_Channel_1,?&DAC_InitStructure);
????
????
????/*?enable?DAC0?and?set?data?*/
????DAC_Cmd(DAC_Channel_1,?ENABLE);
????DAC_SoftwareTriggerCmd(DAC_Channel_1,?ENABLE);
????DAC_SetChannel1Data(DAC_Align_12b_R,?0);
}

GD32

void?dac1_init(void)
{
????rcu_periph_clock_enable(RCU_GPIOA);
????rcu_periph_clock_enable(RCU_DAC);

????gpio_mode_set(GPIOA,?GPIO_MODE_ANALOG,?GPIO_PUPD_NONE,?GPIO_PIN_4);

????dac_deinit();

????/*?software?trigger?*/
????dac_trigger_enable(DAC0);
????dac_trigger_source_config(DAC0,?DAC_TRIGGER_SOFTWARE);

????/*?no?noise?wave?*/
????dac_wave_mode_config(DAC0,?DAC_WAVE_DISABLE);

????/*?noise?wave?-?triangle?*/
????//dac_wave_mode_config(DAC0,?DAC_WAVE_MODE_TRIANGLE);
????//dac_triangle_noise_config(DAC0,?DAC_TRIANGLE_AMPLITUDE_4095);
????/*?noise?wave?-?lfsr?*/
????//dac_wave_mode_config(DAC0,?DAC_WAVE_MODE_LFSR);
????//dac_lfsr_noise_config(DAC0,?DAC_LFSR_BITS11_0);
????
????dac_output_buffer_enable(DAC0);
????
????/*?enable?DAC0?and?set?data?*/
????dac_enable(DAC0);
????dac_software_trigger_enable(DAC0);
????dac_data_set(DAC0,?DAC_ALIGN_12B_R,?0);
}

DAC的噪声波

有两种方式可以将噪声波加载到 DAC 输出数据:LFSR 噪声波和三角波。

具体参见初始化中的配置项。

三角波的波形如下所示:

e4ea5a00dea6a3ebb4d4f428e1469bd6.png

LFSR噪声波的波形如下所示:

9bec180783eb66be3515e48f32dffeda.png

DAC波形发生器

如何通过DAC产生任意频率的周期性波形?

对于一个周期性波形,实际上它是一个时间的函数,即:y=f(t)

抽象一把,我们要解决2个问题:

  1. x轴时间如何采样?

  2. y轴数据如何计算?

数学推导 - x轴

假设频率为f,周期为T(T=1/f),采样点数为M:

那么△t = T/M,当给定频率f时,M=1/(△t*f)

在软件逻辑中,△t是定时器周期,为已知变量。

e3e0a61a562362e1e235c83861d73194.png

【注:请复习下奈奎斯特定理】

数学推导 - y轴 方波

如下数学推导中,MAX为幅值。

y?=?0?if?p?<?M/2?else?MAX
ed3317adab0244a5bd6058a9d89bb8c8.png
1HZ方波

数学推导 - y轴 三角波

y?=?p*MAX/(M/2)?if?p?<?M/2?else?(M-p)*MAX/(M/2)
83da9d967f7d54d765c17a3aded152eb.png
1HZ三角波

数学推导 - y轴 正弦波

正弦波可以用数学库中的sin函数来计算,但是比较费事,可以通过角度查表的方式来计算。

另外,由于sin函数包含负值,需要将数据向上平移到正值(+1)。

rad?=?360*p/M
y?=?(sin_table(rad)?+?1)?*?MAX/2

0-90°的sin函数表如下所示:

const?float?sinus_I_quarter[91]?=
{
????0.0000,?0.0175,?0.0349,?0.0523,?0.0698,?0.0872,?0.1045,?0.1219,?0.1392,?0.1564,?//?00?..?09
????0.1736,?0.1908,?0.2079,?0.2250,?0.2419,?0.2588,?0.2756,?0.2924,?0.3090,?0.3256,?//?10?..?19
????0.3420,?0.3584,?0.3746,?0.3907,?0.4067,?0.4226,?0.4384,?0.4540,?0.4695,?0.4848,?//?20?..?29
????0.5000,?0.5150,?0.5299,?0.5446,?0.5592,?0.5736,?0.5878,?0.6018,?0.6157,?0.6293,?//?30?..?39
????0.6428,?0.6561,?0.6691,?0.6820,?0.6947,?0.7071,?0.7193,?0.7314,?0.7431,?0.7547,?//?40?..?49
????0.7660,?0.7771,?0.7880,?0.7986,?0.8090,?0.8192,?0.8290,?0.8387,?0.8480,?0.8572,?//?50?..?59
????0.8660,?0.8746,?0.8829,?0.8910,?0.8988,?0.9063,?0.9135,?0.9205,?0.9272,?0.9336,?//?60?..?69
????0.9397,?0.9455,?0.9511,?0.9563,?0.9613,?0.9659,?0.9703,?0.9744,?0.9781,?0.9816,?//?70?..?79
????0.9848,?0.9877,?0.9903,?0.9925,?0.9945,?0.9962,?0.9976,?0.9986,?0.9994,?0.9998,?//?80?..?89
????1.0000??????????????????????????????????????????????????????????????????????????//?90
};

由于sin函数的对称性,91°~360°可以通过数学公式推导得到:

#define?CIRCLE_QUARTER_1????????1
#define?CIRCLE_QUARTER_2????????2
#define?CIRCLE_QUARTER_3????????3
#define?CIRCLE_QUARTER_4????????4

float?sinus_lookup?(unsigned?int?angle)
{
????float?sin_value;
????unsigned?int?circle_quarter;

????//?correct?angles?outside?the?accepted?angle?range?into?0?..?359
????if?(angle?>?359u)
????????angle?=?angle?%?360u;

????circle_quarter?=?1?+?(angle?/?90u);

????switch?(circle_quarter)
????{
????????case?CIRCLE_QUARTER_1:?//?00?..?89
????????????sin_value?=?sinus_I_quarter[angle];
????????????break;

????????case?CIRCLE_QUARTER_2:?//?90?..?179
????????????sin_value?=?sinus_I_quarter[180?-?angle];
????????????break;

????????case?CIRCLE_QUARTER_3:?//?180?..?269
????????????sin_value?=?-sinus_I_quarter[angle?-?180];
????????????break;

????????case?CIRCLE_QUARTER_4:?//?270?..?359
????????????sin_value?=?-sinus_I_quarter[360?-?angle];
????????????break;
????}

????return?sin_value;
}
5cb476a6ba5bbb906c846f780cede0eb.png
1HZ正弦波
2c7ddaae7c681709c404f8bb95bc6310.png
100HZ正弦波

程序设计

波形程序

我们通过一个0.1ms的定时器作为△t,在定时中断函数中执行绘图函数。

void?plot_sin(uint32_t?f,?uint32_t?delta_f)
{
????/*?定时周期为T=1/delta_f,?f=1/(pMax*T)?*/
????static?uint32_t?point?=?0;
????uint32_t?pMAX?=?delta_f/f;
????uint32_t?value?=?0;
????
????if?(point++?>?pMAX)?point?=?0;????
????value?=?(uint32_t)((sinus_lookup(360*point/pMAX)+1)*10000)*2047/10000;
????
????dac_software_trigger_enable(DAC0);
????dac_data_set(DAC0,?DAC_ALIGN_12B_R,?value);
}

void?plot_triangle(uint32_t?f,?uint32_t?delta_f)
{
????/*?定时周期为T=1/delta_f,?f=1/(pMax*T)?*/
????static?uint32_t?point?=?0;
????uint32_t?pMAX?=?delta_f/f;
????uint32_t?pMAX2?=?pMAX/2;
????uint32_t?value?=?0;
????
????if?(++point?>?pMAX)?point?=?0;

????if?(point?<?pMAX2)
????{
????????value?=?point?*?4095?/?pMAX2;
????}
????else
????{
????????value?=?(pMAX?-?point)?*?4095?/?pMAX2;
????}

????dac_software_trigger_enable(DAC0);
????dac_data_set(DAC0,?DAC_ALIGN_12B_R,?value);
}

void?plot_square(uint32_t?f,?uint32_t?delta_f)
{
????/*?定时周期为T=1/delta_f,?f=1/(pMax*T)?*/
????static?uint32_t?point?=?0;
????uint32_t?pMAX?=?delta_f/f;
????uint32_t?pMAX2?=?pMAX/2;
????uint32_t?value?=?0;
????
????if?(++point?>?pMAX)?point?=?0;

????if?(point?<?pMAX2)
????{
????????value?=?0;
????}
????else
????{
????????value?=?0xFFF;
????}

????dac_software_trigger_enable(DAC0);
????dac_data_set(DAC0,?DAC_ALIGN_12B_R,?value);
}

GD32的定时器配置和中断:

void?timer3_init(void)
{
????timer_deinit(TIMER2);
????rcu_periph_clock_enable(RCU_TIMER2);
????timerx_init(TIMER2,?999,?9);??//?100KHz?0.1ms
????timer_interrupt_enable(TIMER2,?TIMER_INT_UP);
????nvic_irq_enable(TIMER2_IRQn,?1,?2);
}

void?TIMER2_IRQHandler(void)
{
#ifdef?DAC_WAVE_TEST
????plot_sin(100,?10000);
????//plot_triangle(1,?10000);
????//plot_square(1,?10000);
#endif
????timer_interrupt_flag_clear(TIMER2,?TIMER_INT_FLAG_UP);
}

兼容设计

#ifdef?STM32

#define?DAC0?DAC_Channel_1
#define?DAC1?DAC_Channel_2

#define?DAC_ALIGN_12B_R?DAC_Align_12b_R

#define?dac_software_trigger_enable(channel)?DAC_SoftwareTriggerCmd(channel,?ENABLE)
#define?dac_data_set(DAC_Channel_1,?align,?value)?DAC_SetChannel1Data(align,?value)
#endif

例行结果展示

1HZ方波

8be857c3bfbf5ed6f9f855b6b5634e34.gif
1HZ正弦波

1HZ三角波

9a600b0818dbf407fe92db61dde9f7d4.gif
1HZ三角波

1HZ正弦波

173034634922b468f911ce64c3960d6d.gif
1HZ正弦波

100HZ正弦波

0d519164c1b34ccd7dabed07f3bc50c2.gif
100HZ正弦波

GD正弦波和STM方波1HZ

53a2030d0a6d5b80d38d5f49e14005ff.gif

GD正弦波和ST M方波1HZ

--EOF--

例行求粉,谢谢!

7319dd05e578bb408bcc9996485af5db.png
求粉
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-20 15:56:14  更:2021-09-20 15:56:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:20:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码