4570|3

530

帖子

4

TA的资源

一粒金砂(高级)

楼主
 

[GD32E231 DIY大赛] 06. 自动喂鱼机器人之ADC/DMA/TIMER0/串口篇 [复制链接]

 
[GD32E231 DIY大赛] 06. 自动喂鱼机器人之ADC/DMA/TIMER0/串口篇

这里用到了光敏电阻来监测鱼缸周围的光照度。

从内部ADC采集,定时器0的比较事件0触发ADC转换,ADC转换的结果将随着模拟值输入的改变而改变。

转换结果由DMA 搬运到SRAM 中,最后判断AD的值是否大于一定数值。
具体程序如下:
首先涉及以下函数和变量:
  1. __IO uint16_t ad_value[220];  //day:ad_value <1500;night:ad_value>2500

  2. void adc_rcu_config(void);
  3. void adc_gpio_config(void);
  4. void adc_dma_config(void);
  5. void adc_timer_config(void);
  6. void adc_config(void);
  7. void display_adc_value(void);
复制代码
  1. /*!
  2.     \brief      RCU configuration function for ADC
  3.     \param[in]  none
  4.     \param[out] none
  5.     \retval     none
  6. */
  7. void adc_rcu_config(void)
  8. {
  9.     /* enable the GPIO clock */
  10.     //rcu_periph_clock_enable(RCU_GPIOA);
  11.     //rcu_periph_clock_enable(RCU_GPIOB);
  12.     //rcu_periph_clock_enable(RCU_GPIOC);
  13.    // rcu_periph_clock_enable(RCU_GPIOF);

  14.     /* ADCCLK = PCLK2/6 */
  15.     rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);

  16.     /* enable DMA clock */
  17.     rcu_periph_clock_enable(RCU_DMA);

  18.     /* enable ADC clock */
  19.     rcu_periph_clock_enable(RCU_ADC);

  20.     /* enable TIMER0 clock */
  21.     rcu_periph_clock_enable(RCU_TIMER0);
  22. }
  23. /*!
  24.     \brief      GPIO configuration function for ADC
  25.     \param[in]  none
  26.     \param[out] none
  27.     \retval     none
  28. */
  29. void adc_gpio_config(void)
  30. {
  31.     /* configure PA2(ADC channel2) as analog input */
  32.     gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
  33. }
  34. /*!
  35.     \brief      DMA configuration function for ADC
  36.     \param[in]  none
  37.     \param[out] none
  38.     \retval     none
  39. */
  40. void adc_dma_config(void)
  41. {
  42.     dma_parameter_struct dma_init_struct;

  43.     /* initialize DMA channel0 */
  44.     dma_deinit(DMA_CH0);
  45.     dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
  46.     dma_init_struct.memory_addr  = (uint32_t)ad_value;
  47.     dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
  48.     dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
  49.     dma_init_struct.number       = 220;
  50.     dma_init_struct.periph_addr  = (uint32_t)&(ADC_RDATA);
  51.     dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
  52.     dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
  53.     dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
  54.     dma_init(DMA_CH0, &dma_init_struct);
  55.    
  56.     /* configure DMA mode */
  57.     dma_circulation_enable(DMA_CH0);
  58.     dma_memory_to_memory_disable(DMA_CH0);
  59.    
  60.     /* enable DMA channel0 */
  61.     dma_channel_enable(DMA_CH0);
  62. }

  63. /*!
  64.     \brief      TIMER configuration function for ADC
  65.     \param[in]  none
  66.     \param[out] none
  67.     \retval     none
  68. */
  69. void adc_timer_config(void)
  70. {
  71.     timer_oc_parameter_struct timer_ocintpara;
  72.     timer_parameter_struct timer_initpara;

  73.     timer_deinit(TIMER0);

  74.     /* TIMER0 configuration */
  75.     timer_initpara.prescaler         = 5;
  76.     timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
  77.     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
  78.     timer_initpara.period            = 399;
  79.     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
  80.     timer_initpara.repetitioncounter = 0;
  81.     timer_init(TIMER0, &timer_initpara);

  82.     /* CH0 configuration in PWM mode1 */
  83.     timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_LOW;
  84.     timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
  85.     timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);

  86.     timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 100);
  87.     timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM1);
  88.     timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);

  89.     /* auto-reload preload enable */
  90.     timer_auto_reload_shadow_enable(TIMER0);
  91.     timer_primary_output_config(TIMER0, ENABLE);
  92. }

  93. /*!
  94.     \brief      ADC configuration function
  95.     \param[in]  none
  96.     \param[out] none
  97.     \retval     none
  98. */
  99. void adc_config(void)
  100. {
  101.     /* ADC channel length config */
  102.     adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);

  103.     /* ADC regular channel config */
  104.     adc_regular_channel_config(0, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5);

  105.     /* ADC external trigger enable */
  106.     adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
  107.     /* ADC external trigger source config */
  108.     adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T0_CH0);
  109.     /* ADC data alignment config */
  110.     adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
  111.     /* enable ADC interface */
  112.     adc_enable();
  113.     /* ADC calibration and reset calibration */
  114.     adc_calibration_enable();
  115.     /* ADC DMA function enable */
  116.     adc_dma_mode_enable();
  117. }
  118. void display_adc_value(void)
  119. {
  120.           printf("\r\n%d\r\n",ad_value[0]);
  121. }
复制代码



ad转换我只用了第一个值,其实DMA传输会不停的循环传输。
主函数中这样用:
  1. gd_eval_com_init(EVAL_COM1,115200);
  2.   adc_rcu_config();
  3.     adc_gpio_config();
  4.           adc_dma_config();
  5.     adc_timer_config();
  6.     adc_config();
  7.          /* TIMER0 counter enable for ADC */
  8.     timer_enable(TIMER0);
  9.                 /* test on channel0 transfer complete flag */
  10.                 while( !dma_flag_get(DMA_CH0, DMA_FLAG_FTF));
  11.                 display_adc_value();
复制代码

然后在while(1) 中执行display_adc_value(); 就能把值实时打印到串口。

DMA配置完会不断循环写入到buffer中,配置完成后CPU不需要参与,我们在循环中,可以直接读取AD值,这些值在配置DMA时是循环覆盖写入的。

printf是采用串口显示,
具体方法如下,在keil的魔术棒option里,Target中,勾选Use MicroLIB, 然后添加如下子程序,重新映射串口,
  1. /* retarget the C library printf function to the USART */
  2. int fputc(int ch, FILE *f)
  3. {
  4.     usart_data_transmit(EVAL_COM1, (uint8_t)ch);
  5.     while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));

  6.     return ch;
  7. }
复制代码


关于串口初始化:gd_eval_com_init(EVAL_COM1,115200);
其是在gd32e231c_start.c、gd32e231c_start.h中定义的:
gd32e231c_start.h
  1. //-----------------added by user--------------------------//
  2. /* eval board low layer COM */
  3. #define COMn                             1U   //定义数组大小

  4. /* definition for COM0, connected to USART0 */
  5. #define EVAL_COM1                        USART0
  6. #define EVAL_COM1_CLK                    RCU_USART0

  7. #define EVAL_COM1_TX_PIN                 GPIO_PIN_9
  8. #define EVAL_COM1_RX_PIN                 GPIO_PIN_10

  9. #define EVAL_COM_GPIO_PORT               GPIOA
  10. #define EVAL_COM_GPIO_CLK                RCU_GPIOA
  11. #define EVAL_COM_AF                      GPIO_AF_1

  12. /* configure COM port */
  13. void gd_eval_com_init(uint32_t com, uint32_t baud);
复制代码




gd32e231c_start.c
  1. static rcu_periph_enum COM_CLK[COMn]  = {EVAL_COM1_CLK};

  2. static uint32_t COM_TX_PIN[COMn]      = {EVAL_COM1_TX_PIN};

  3. static uint32_t COM_RX_PIN[COMn]      = {EVAL_COM1_RX_PIN};
复制代码


  1. void gd_eval_com_init(uint32_t com, uint32_t baud)
  2. {
  3.     uint32_t COM_ID;
  4.   
  5.     if(EVAL_COM1 == com){
  6.         COM_ID = 0U;
  7.     }else{
  8.     }

  9.     /* enable COM GPIO clock */
  10.     rcu_periph_clock_enable(EVAL_COM_GPIO_CLK);

  11.     /* enable USART clock */
  12.     rcu_periph_clock_enable(COM_CLK[COM_ID]);

  13.     /* connect port to USARTx_Tx */
  14.     gpio_af_set(EVAL_COM_GPIO_PORT, EVAL_COM_AF, COM_TX_PIN[COM_ID]);

  15.     /* connect port to USARTx_Rx */
  16.     gpio_af_set(EVAL_COM_GPIO_PORT, EVAL_COM_AF, COM_RX_PIN[COM_ID]);

  17.     /* configure USART Tx as alternate function push-pull */
  18.     gpio_mode_set(EVAL_COM_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, COM_TX_PIN[COM_ID]);
  19.     gpio_output_options_set(EVAL_COM_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, COM_TX_PIN[COM_ID]);

  20.     /* configure USART Rx as alternate function push-pull */
  21.     gpio_mode_set(EVAL_COM_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, COM_RX_PIN[COM_ID]);
  22.     gpio_output_options_set(EVAL_COM_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, COM_RX_PIN[COM_ID]);

  23.     /* USART configure */
  24.     usart_deinit(com);
  25.    // usart_baudrate_set(com, 115200U);
  26.           usart_baudrate_set(com, baud);
  27.     usart_receive_config(com, USART_RECEIVE_ENABLE);
  28.     usart_transmit_config(com, USART_TRANSMIT_ENABLE);

  29.     usart_enable(com);
  30. }
复制代码



注意串口0还是1。
-------------------------------------------



最新回复

谢谢分享   详情 回复 发表于 2021-4-22 17:31

赞赏

1

查看全部赞赏

点赞(1) 关注(1)
 
 

回复
举报

121

帖子

1

TA的资源

一粒金砂(中级)

沙发
 

timer 触发一次AD,AD采样一次,完成一次采样后触发DMA,DMA填写一次缓存ad_value[220]

timer 触发220次AD,ad_value[220]写满后,DMA会自动循环从ad_value[0]开始重新填写

 

不知道这样理解对不对

 

 
 
 

回复

1942

帖子

3

TA的资源

版主

板凳
 

最近山东不是要举办机器人设计大赛嘛。

 
 
 

回复

661

帖子

0

TA的资源

纯净的硅(初级)

4
 

谢谢分享

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表