查看: 809|回复: 1

【瑞萨RA4系列开发板体验】用两路DAC在示波器上显示一...

[复制链接]

116

主题

134

帖子

3778

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3778
发表于 2023-2-8 16:13:53 | 显示全部楼层 |阅读模式
【瑞萨RA4系列开发板体验】用两路DAC在示波器上显示一个爱心
作者:hehung

前言
前面已经开了一篇帖子来描述DAC如何使用了,为什么又要写一篇呢,那是因为我发现DAC结合示波器能玩出一些新花样,将示波器设置为XY模式之后就可以用来显示李萨如图像,通过sin函数以及cos函数的变形就可以显示出不同图案的数据,如果有精力和时间的话,显示动画,打游戏都是不是问题。
其实本文已经在其他平台发布过了,只不过是针对示波器的试用,使用了该单片的DAC输出波形,让示波器显示一个跳动的爱心。因为是基于RA4M2来制作的,所以也将流程在此处发布一下,也算是对RA4M2的一个试用方向。

XY模式简单介绍
示波器都可以设置为XY模式,就是一路信号作为X轴,一路信号作为Y轴,两路信号相交的位置就显示点,根据该模式的特性,可以显示图形。

实验环境
信号源:瑞萨RA4M2单片机两路DAC,精度为12bit,最大输出值为4096,最大输出电压为3.3V;
DS100:两路示波器信号输入,CHA作为X轴,CHB作为Y轴。

输出正弦信号
详见我之前关于DAC那篇文章描述。
、首先是测试单片机的DAC模块是否能够正常输出正弦信号,这是后面试验的基础,设置时基模式为ROLLO机会YT。
然后编写一个测试代码:如下:
其中,sin(xxx) * 2048 + 2048的目的是将DAC输出信号编程一个正数。
让DAC0输出正弦波,DAC1输出余弦波。
其中time_cnt就是0~2π,每次的增长周期为0.05,没1毫秒增长一次,这样可以让波形看起来更新连续,如果需要增加进行精度,可以修改为更小的值。
实现原理:
因为DAC不能输出负电压,所以需要将sin计算出来的负数部分进行偏移,实现原理见下方代码,sin最小值为-1,所以将DAC输出值偏移2048,然后加上剩余值2048,当sin计算值-1的时候,DAC则输出0,当sin计算值为1的时候,DAC输出4096。

  1. dac_value[0] = (uint16_t)(sin(time_cnt) * (float)2048) + 2048;
  2. dac_value[1] = (uint16_t)(sin(time_cnt + 0.5*PI_MATH) * (float)2048) + 2048;

  3. Adc_OutputVal(DAC_DAC0, dac_value[0]);
  4. Adc_OutputVal(DAC_DAC1, dac_value[1]);
复制代码


测试李萨如图像
1输出一个圆
使用单片机输出两路DAC正弦信号,使用了C语言标准库的sin函数,两路正弦波信号有相位差,相位差为0的时候显示的是一条斜线,随着相位差增加,会变为一个椭圆,当相位差为π/2的时候就会显示成一个圆形。

2输出变动的李萨如图像
调整DAC0与DAC1输出正弦信号的相位差就可以改变李萨如图像为椭圆或者斜线,见下视频。
代码中只需要修改DAC1输出的信号的相位差即可,其中change应该随着时间变化,变化的周期自行编写,最好是一个完整的sin信号输出周期之后在改变,不然图形显示不完整。
  1. dac_value[1] = (uint16_t)(sin(time_cnt + change*PI_MATH) * (float)2048) + 2048;
复制代码
演示视频
3输出一个有大小可变的圆
设置DAC0与DAC1的输出正弦信号的相位差为π/2,然后修改输出信号的幅值就可以修改圆形的半径,其中半径R_circle为周期可变的。
将上述中的偏移值2048设置为一个可变值,让它随着时间变化,则可以改变椭圆的半径,如下:

  1. dac_value[0] = (uint16_t)(sin(time_cnt) * (float)R_circle) + R_circle;
  2. dac_value[1] = (uint16_t)(sin(time_cnt + 0.5*PI_MATH) * (float)R_circle) + R_circle;

  3. Adc_OutputVal(DAC_DAC0, dac_value[0]);
  4. Adc_OutputVal(DAC_DAC1, dac_value[1]);

  5. if (time_cnt > PI_DOUBLE)
  6. {
  7.                 time_cnt = 0.0f;
  8.                
  9.                 R_circle -= 20;
  10.                 if (R_circle <= 100)
  11.                                 R_circle = 2048;
  12. }
  13. else
  14. {
  15.                 time_cnt += 0.05f;
  16. }
复制代码
演示视频
输出爱心
知道了上面的原理之后,我们可以用sin以及cos输出一个爱心,计算公式如下:
x = 2sin(t)+sin(2t);
y = -(2cos(t)+cos(2t));
同上述原理,DAC不能输出负数,y轴最小值会输出-3,所以我们需要将DAC的输出值分成6份,用于抵消负数,实现代码如下:
需要注意的是,测试中需要自己调整示波器的刷新频率以及单片机输出信号的切换频率,让两者保持在一个平衡点之后,刷新出来的爱心跳动才会稳定,不然会有一个余辉影响视觉效果。


视频演示

完整代码实现
代码写的比较乱,但是逻辑相对简单,还是比较容易理解。
  1. #define POLT_MODE        1
  2. #define PI_MATH           (3.14)
  3. #define PI_DOUBLE         (PI_MATH * 2)
  4. uint16_t dac_value[2];
  5. double time_cnt;
  6. double change = 0;
  7. uint16_t change_up_cnt = 0;
  8. uint16_t R_circle = 2048;

  9. uint16_t love_R = 682;
  10. uint8_t  love_flg = 0;
  11. uint8_t  love_chane_t = 0;

  12. double my_cos(double time_)
  13. {
  14.         return sin(time_ + 0.5*PI_MATH);
  15. }
  16. void hal_entry(void)
  17. {
  18.         /* Initialize the uart for implement the 'printf' and 'scanf' */
  19.         Uart_Init();
  20.         /* Initialize the I2c */
  21.         I2c_Init();
  22.         /* Initialize the OLED */
  23.         OLED_Init();
  24.         /* Initialize the ADC */
  25.         Adc_Init();
  26.         /* Initialize the DAC */
  27.         Dac_Init();
  28.        
  29.         OLED_ShowHzStringRow(8, 0, (const char*)"正点原子示波器", 1);
  30.     OLED_ShowString(8, 16, (const uint8_t*)"elecfans|hehung", 16, 1);
  31.         OLED_ShowString(16, 32, (const uint8_t*)"XY Mode Test", 16, 1);
  32.     OLED_Refresh_Gram();
  33.        
  34.         while (1)
  35.         {
  36. #if (POLT_MODE == 0)
  37.                 /* 输出李萨如图像 */
  38.                 dac_value[0] = (uint16_t)(sin(time_cnt) * (float)2048) + 2048;
  39.                 dac_value[1] = (uint16_t)(sin(time_cnt + change*PI_MATH) * (float)2048) + 2048;

  40.                 Adc_OutputVal(DAC_DAC0, dac_value[0]);
  41.                 Adc_OutputVal(DAC_DAC1, dac_value[1]);
  42.                
  43.                 if (time_cnt > PI_DOUBLE)
  44.                 {
  45.                         time_cnt = 0.0f;
  46.                         change_up_cnt = 0U;
  47.                         change += 0.01f;
  48.                                
  49.                         if (change > PI_DOUBLE)
  50.                         {
  51.                                 change = 0.0f;
  52.                         }
  53.                 }
  54.                 else
  55.                 {
  56.                         time_cnt += 0.05f;
  57.                 }
  58. #elif (POLT_MODE == 1)
  59.                 /* 输出爱心 */
  60.                 double x = (2 * sin(time_cnt) + sin(2 * time_cnt));
  61.                 double y = (2 * cos(time_cnt) + cos(2 * time_cnt));

  62.                 dac_value[0] = 4096-((uint16_t)((x * (float)love_R) + (3*love_R)));
  63.                 dac_value[1] = 4096-((uint16_t)((y * (float)love_R) + (3*love_R)));

  64.                 Adc_OutputVal(DAC_DAC0, dac_value[0]);
  65.                 Adc_OutputVal(DAC_DAC1, dac_value[1]);
  66.                 if (time_cnt > PI_DOUBLE)
  67.                 {
  68.                         time_cnt = 0.0f;
  69.                        
  70.                         love_chane_t ++;
  71.                        
  72.                         if (love_chane_t > 10)
  73.                         {
  74.                                 love_chane_t = 0;
  75.                                 love_R = (love_flg == 0) ? (love_R - 40) : (love_R + 40);
  76.                                 love_flg ^= 1;
  77.                         }
  78.                 }
  79.                 else
  80.                 {
  81.                         time_cnt += 0.05f;
  82.                 }
  83. #else
  84.                 /* 输出李萨如图像 */
  85.                 dac_value[0] = (uint16_t)(sin(time_cnt) * (float)R_circle) + R_circle;
  86.                 dac_value[1] = (uint16_t)(sin(time_cnt + 0.5*PI_MATH) * (float)R_circle) + R_circle;

  87.                 Adc_OutputVal(DAC_DAC0, dac_value[0]);
  88.                 Adc_OutputVal(DAC_DAC1, dac_value[1]);
  89.                
  90.                 if (time_cnt > PI_DOUBLE)
  91.                 {
  92.                         time_cnt = 0.0f;
  93.                        
  94.                         R_circle -= 20;
  95.                         if (R_circle <= 100)
  96.                                 R_circle = 2048;
  97.                 }
  98.                 else
  99.                 {
  100.                         time_cnt += 0.05f;
  101.                 }
  102. #endif
  103.                 R_BSP_SoftwareDelay(210, BSP_DELAY_UNITS_MICROSECONDS);
  104.         }

  105. #if BSP_TZ_SECURE_BUILD
  106.     /* Enter non-secure code */
  107.     R_BSP_NonSecureEnter();
  108. #endif
  109. }
复制代码


总结
从这个试验可以看出,RA4M2的DAC能够满足基本的电压输出需求,能够满足快速变换电压的输出请求,而且DAC使用起来也十分的方便。

回复

使用道具 举报

3

主题

195

帖子

1510

积分

金牌会员

Rank: 6Rank: 6

积分
1510
发表于 2023-3-14 10:31:57 | 显示全部楼层

挺好玩的,不错
回复

使用道具 举报

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

本版积分规则

用户排行榜

RA助手

主题: 116帖子:134精华:0

RA_Lance

主题: 92帖子:132精华:9

lugl

主题: 44帖子:133精华:0

xujiwei263

主题: 16帖子:73精华:0

books咦

主题: 11帖子:11精华:2

Juggernaut

主题: 9帖子:95精华:0
快速回复 返回顶部 返回列表