GD32 Timer+ADC多通道+DMA+PWM調試記錄

本例記錄使用GD32307C開發板,實現以內部Timer1 CH1為觸發源,觸發ADC0的兩個通道,進行并行非連續采樣,病通過DMA傳輸采樣結果。同時輸出PWM,用來檢測Timer1 CH1的觸發周期。

下面介紹具體實現過程:

1. gpio初始化

本例需要用到以下三根IO:

PA1 -- TIMER1_1,PWM
PC3 -- ADC0_CH13
PC5 -- ADC0_CH15

查詢芯片手冊需要將PC3/PC5設定為模擬輸入AIN(ADC功能),將PA1設定為備份功能輸出腳AF_PP(PWM輸出)。

以PA1為例,設定為Alternate功能后,如果有啟動Timer1,則該腳位的功能為TIMER1_CH1。

  1. 使能GPIO Group時鐘。
  2. 使能Alternate Function時鐘。
  3. GPIO 功能config 。

代碼如下:

/*!\brief      configure the GPIO peripheral\param[in]  none\param[out] none\retval     none
*/
//PA1 -- TIMER1_1,PWM
//PC3 -- ADC0_CH13
//PC5 -- ADC0_CH15
static void gpio_config(void)
{/* enable GPIOC clock */rcu_periph_clock_enable(RCU_GPIOC);rcu_periph_clock_enable(RCU_GPIOA); /* 開啟復用功能時鐘 */rcu_periph_clock_enable(RCU_AF);	/* config the GPIO as analog mode */  gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_3|GPIO_PIN_5);/*configure PB3(TIMER1 CH1) as alternate function*/gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
}

2.Timer初始化

這里配置Timer1的定時周期為1ms,附上Timer時間公式:

定時時間:Time= (1+prescaler)/ systemcoreclock *(1+period)

我這邊systemcoreclock為120MHZ。

設定CH1位PWM0模式輸出,用來驗證ADC采樣間隔(ADC采樣以內部Timer1_CH1為觸發源)。

在下面代碼里面,我們設定為邊沿對齊方式(EAPWM),向上計數:

EAPWM的周期由TIMERx_CAR寄存器值決定,占空比由TIMERx_CHxCV寄存器值決定。

這里介紹一下PWM的工作模式(PWM0/PWM1)

PWM的工作模式:

  • PWM 模式0。在向上計數時,一旦計數器值小于TIMERx_CH0CV時,
    O0CPRE為有效電平,否則為無效電平。在向下計數時,一旦計數器的值大
    于TIMERx_CH0CV時,O0CPRE 為無效電平,否則為有效電平。
  • PWM 模式1。在向上計數時,一旦計數器值小于TIMERx_CH0CV時,
    O0CPRE為無效電平,否則為有效電平。在向下計數時,一旦計數器的值大
    于TIMERx_CH0CV時,O0CPRE為有效電平,否則為無效電平。

占空比計算公式:

Duty = A/(N+1)? ?

N = Timer裝載值

A =?TIMER_CHxCV,即timer_channel_output_pulse_value_config的最后一個參數

EAPWM的時序示意圖如下:

代碼如下:

/*!\brief      configure the timer peripheral\param[in]  none\param[out] none\retval     none
*/
static void timer1_config(void)	// 1 ms
{timer_oc_parameter_struct timer_ocintpara;timer_parameter_struct timer_initpara;//使能定時器時鐘rcu_periph_clock_enable(RCU_TIMER1);timer_deinit(TIMER1);/*  TIMER1 基本配置 */timer_initpara.prescaler				 = 119;timer_initpara.alignedmode			 = TIMER_COUNTER_EDGE;timer_initpara.counterdirection  = TIMER_COUNTER_UP;timer_initpara.period 					 = 999;timer_initpara.clockdivision		 = TIMER_CKDIV_DIV1;timer_initpara.repetitioncounter = 0;timer_init(TIMER1,&timer_initpara);/* CH1 configuration in PWM mode1 */timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;		/* 通道使能 */    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;		/* 通道互補輸出使能(定時器2無效) */    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;	/* 通道極性 */    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;/* 互補通道極性(定時器2無效)*/    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;/* 通道空閑狀態輸出(定時器2無效)*/    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;/*互補通道空閑狀態輸出(定時器2無效) */timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocintpara);/* duty 占空比設定*/timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 500);timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM0);timer_channel_output_shadow_config(TIMER1, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);timer_auto_reload_shadow_enable(TIMER1);
}

使用示波器量測PA1腳位,輸出為1KHZ的方波。

3. dma初始化

這里我們選擇DMA0_CH0,這里我們設定為16bit寬度數據源,與16bit外設數據寬度。DMA傳輸數量設定為100.

所以我們定義一個100 uint16_t的數組作為DMA存放數據的內存。

開啟半滿與全滿中斷。

代碼如下:

/*!\brief      configure the DMA peripheral\param[in]  none\param[out] none\retval     none
*/
uint16_t adc_value[100];
uint32_t dmaHalfIntCnt; static void dma_config(void)
{/* ADC_DMA_channel configuration */dma_parameter_struct dma_data_parameter;/* enable DMA clock */rcu_periph_clock_enable(RCU_DMA0);/* 復位dma 通道0  */dma_deinit(DMA0, DMA_CH0);/* initialize DMA data mode */dma_data_parameter.periph_addr	= (uint32_t)(&ADC_RDATA(ADC0));//配置外設寄存器為adc的規則數據寄存器dma_data_parameter.periph_inc 	= DMA_PERIPH_INCREASE_DISABLE;//外設寄存器地址不增加dma_data_parameter.memory_addr	= (uint32_t)(&adc_value);//存放數據的內存地址dma_data_parameter.memory_inc 	= DMA_MEMORY_INCREASE_ENABLE;//存放數據的內存地址自增dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//外設數據寬度32位 adc1[16-31]adc0[0-15]dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;  //內存數據寬度32位dma_data_parameter.direction		= DMA_PERIPHERAL_TO_MEMORY;//數據傳輸方式是外設到內存dma_data_parameter.number 			= 100;//dma傳輸數量dma_data_parameter.priority 		= DMA_PRIORITY_HIGH;//dma優先級高dma_init(DMA0, DMA_CH0, &dma_data_parameter);//循環模式開啟dma_circulation_enable(DMA0, DMA_CH0);/* dam 轉換結束產生中斷*/dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF);		dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_HTF);	/* 使能dma通道0*/dma_channel_enable(DMA0, DMA_CH0);//中斷管理器開啟通道4中斷nvic_irq_enable(DMA0_Channel0_IRQn, 0, 0);	
}

DMA中斷程序如下:(函數名與startup中的中斷向量表函數名一致)

void DMA1_Channel1_IRQHandler(void)
{if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF)){  //清除dma中斷標記dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);gd_eval_led_toggle(LED2);//dma_finish = SET;} else if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_HTF)){//清除dma中斷標記dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_HTF);dmaHalfIntCnt ++;}
}

截取部分Startup_xx.s向量表

g_pfnVectors:

? .
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.

4. ADC初始化

我們使用ADC0的CH13/CH15兩個通道,這里設置ADC為規則并行模式。

開啟掃描模式,ADC會自動采樣轉換開啟的通道。

不要開啟連續掃描,采用間斷掃描方式。

設定TIM1_CH1為外部觸發源,病使能ADC的DMA mode,具體代碼如下:

/*!\brief      configure the ADC peripheral\param[in]  none\param[out] none\retval     none
*/
static void adc_config(void)
{/* enable ADC0 clock */rcu_periph_clock_enable(RCU_ADC0);/* reset ADC */adc_deinit(ADC0);/* ADC mode config 工作在規則并行模式 *///adc_mode_config(ADC_MODE_FREE); adc_mode_config(ADC_DAUL_REGULAL_PARALLEL); // 連續轉換模式使能//adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);/* ADC continous function enable *///adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE); adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE); /* 右對齊*/adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);/* 配置規則通道數量 *///adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2);/* ADC規則模式配置;2個adc并行模式下,不可以2個adc同時采集一個通道,adc1數據放在高16位,adc0數據放在低16位*/adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_13, ADC_SAMPLETIME_55POINT5);adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_15, ADC_SAMPLETIME_55POINT5);/* adc 使用TIM1 的CH1 的上升沿觸發*/adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T1_CH1);/* adc觸發使能*/adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);/* 使能ADC*/adc_enable(ADC0);delay_1ms(1U);/* 標定復位ADC */adc_calibration_enable(ADC0);/* ADC DMA 使能*/adc_dma_mode_enable(ADC0);
}

5. 測試代碼

這里創建一個thread來測試,測試代碼如下:

void LED1_Task(void* parameter)
{gpio_config();timer1_config();dma_config();adc_config();timer_enable(TIMER1);while(1){//gd_eval_led_toggle(LED3);printf("%s tick:%d \n",__FUNCTION__,xTaskGetTickCount());		//Ben 221024#1printf("dmaHalfIntCnt:%d \n",dmaHalfIntCnt);printf("%d %d %d %d\n",adc_value[0],adc_value[1],adc_value[2],adc_value[3]);		vTaskDelay(500); }
}

在500ms間隔下的測試結果為:

dmaHalfIntCnt:2410?
1663 0 1663 1
LED1_Task tick:120965?
dmaHalfIntCnt:2420?
1663 1 1663 0
LED1_Task tick:121469?
dmaHalfIntCnt:2430?
1663 0 1661 1
LED1_Task tick:121973?
dmaHalfIntCnt:2440?
1663 0 1663 0
LED1_Task tick:122477?
dmaHalfIntCnt:2450?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/97878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/97878.shtml
英文地址,請注明出處:http://en.pswp.cn/web/97878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

阻塞 IO為什么叫BIO,非阻塞IO為什么叫NIO,異步IO為什么叫AIO

IOIO的核心就是數據傳輸,也就是程序與外部設備之間進行傳輸,通過IO的核心可以分為,文件IO和網絡IO文件IO交互的對象就是本地存儲設備,比方說讀寫本地文件。網絡IO交互的對象就是網絡設備,核心的應用場景就是網絡通信。…

10分鐘了解什么是多模態大模型

10分鐘了解什么是多模態大模型(MM-LLMs) 1. 什么是多模態 Multimodality 多模態(Multimodality)是指集成和處理兩種或兩種以上不同類型的信息或數據的方法和技術。在機器學習和人工智能領域,多模態涉及的數據類型通常…

通過DSL生成Jenkins流水線

代碼化管理 Jenkins 流水線(Infrastructure as Code) 版本控制:DSL 腳本可以像代碼一樣存入 Git、GitLab 等版本控制系統,所有任務配置的變更都有提交記錄,便于追溯歷史、回滾錯誤。協作效率:團隊成員可以通…

信號量主要API及綜合應用

1.信號量概述信號量是一個底層核心模塊【int】類型變量,記錄當前信號量數據。信號量 P 操作 (sem_wait)線程檢測對應信號量底層 int 數據數值,如果大于 0,當前線程獲得 CPU 執行權,同時將信號量底層 int 數據-1 操作。如果底層數據…

工業自動化領域的“超級跑車”:西門子TDC系統深度解析與實戰架構

工業自動化領域的“超級跑車”:西門子TDC系統深度解析與實戰架構 文章目錄 工業自動化領域的“超級跑車”:西門子TDC系統深度解析與實戰架構引言:當普通PLC遇到性能瓶頸第一章:認識TDC——它不是簡單的“大型PLC”1.1 TDC究竟是什…

MySQL高階查詢語句與視圖實戰指南

MySQL高階查詢語句與視圖實戰指南 文章目錄MySQL高階查詢語句與視圖實戰指南一、常用高階查詢技巧1. 按關鍵字排序(ORDER BY)基礎用法進階用法:多字段排序條件過濾2. 區間判斷與去重(AND/OR DISTINCT)區間判斷&#x…

解決Pytest參數化測試中文顯示亂碼問題:兩種高效方法

在使用Pytest進行參數化測試時,許多開發者都會遇到一個常見但令人頭疼的問題:當測試用例的ids參數包含中文字符時,控制臺輸出會出現亂碼。這不僅影響了測試報告的可讀性,也給測試結果的分析帶來了困難。本文將深入探討這個問題&am…

基于SpringBoot的校園流浪動物救助平臺【spring boot實戰項目、Java畢設、Java項目、Java實戰】

💖💖作者:計算機畢業設計小途 💙💙個人簡介:曾長期從事計算機專業培訓教學,本人也熱愛上課教學,語言擅長Java、微信小程序、Python、Golang、安卓Android等,開發項目包括…

利用kimi k2編寫postgresql協議服務端的嘗試

美團龍貓還是很有自知之明的 提問請用C編寫postgresql協議服務端,能接收psql客戶端或其他采用postgresql協議的工具的請求,實現將用戶請求打印在控制臺,并把回應發給客戶端回答 抱歉,我無法為您編寫完整的 PostgreSQL 協議服務端。…

醫療 AI 再突破:輔助診斷準確率超 90%,但落地醫院仍面臨數據安全與臨床信任難題

一、引言(一)醫療 AI 發展背景在數字化與智能化浪潮的席卷下,醫療領域正經歷著深刻變革,人工智能(AI)技術的融入成為這場變革的關鍵驅動力。近年來,醫療 AI 輔助診斷技術取得重大突破&#xff0…

Rocky Linux10.0安裝zabbix7.4詳細步驟

安裝Rocky Linux10.0系統 請參考Rocky Linux10.0安裝教程-CSDN博客 查看當前系統版本 cat /etc/*release 安裝數據庫 安裝zabbix之前,需要先安裝一個數據庫來承載zabbix的數據。這里我選擇在本機直接安裝一個MariaDB數據庫。 Rocky Linux10.0系統默認不包含MySQ…

JDBC插入數據

文章目錄視頻:JDBC插入數據環境準備寫插入數據屬性配置屬性配置視頻:JDBC插入數據 環境準備 MySQL環境 小皮面板 提供MySQL環境 寫插入數據 屬性配置 聲明變量 屬性配置 # . properties 是一個特俗的map 集合 # key : 字符串 value : 字符串…

GPU 服務器壓力測試核心工具全解析:gpu-burn、cpu-burn 與 CUDA Samples

在 GPU 服務器的性能驗證、穩定性排查與運維管理中,壓力測試是關鍵環節,可有效檢測硬件極限性能、散熱效率及潛在故障。以下從工具原理、核心功能、使用場景等維度,詳細介紹三款核心測試工具,幫助用戶系統掌握 GPU 服務器壓力測試方法。 一、GPU 專屬壓力測試工具:gpu-bu…

Python進程和線程——多線程

前面提到過進程是由很多線程組成的,那么今天廖老師就詳細解釋了線程是如何運行的。首先,,Python的標準庫提供了兩個模塊:_thread和threading,_thread是低級模塊,threading是高級模塊,對_thread進…

【MySQL|第九篇】視圖、函數與優化

目錄 十、視圖 1、簡單視圖: 2、復雜視圖: 3、視圖更新: 十一、函數 1、函數創建: 十二、數據庫優化 1、索引優化: 2、查詢優化: 3、設計優化: 十、視圖 在 MySQL 中,視圖…

使用Docker和虛擬IP在一臺服務器上靈活部署多個Neo4j實例

使用Docker和虛擬IP在一臺服務器上靈活部署多個Neo4j實例 前言 在現代應用開發中,圖數據庫Neo4j因其強大的關系處理能力而備受青睞。但有時候我們需要在同一臺服務器上運行多個Neo4j實例,比如用于開發測試、多租戶環境或者A/B測試。傳統的端口映射方式…

K8s學習筆記(一):Kubernetes架構-原理-組件

Kubernetes(簡稱 K8s)是一款開源的容器編排平臺,核心目標是實現容器化應用的自動化部署、擴展、故障恢復和運維管理。其設計遵循 “主從架構”(Control Plane Node),組件分工明確,通過 “聲明式…

ensp配置學習筆記 比賽版 vlan 靜態路由 ospf bgp dhcp

學習配置VLAN 虛擬局域網,目的讓兩臺在同一網段的設備,在交換機中訪問。基礎指令:sys 進入系統 sysname R1 修改交換機名字為R1 display cur 查看數據、端口等交換機信息 (在端口中,可以直接display this 可以直接看…

倉頡編程語言青少年基礎教程:enum(枚舉)類型和Option類型

倉頡編程語言青少年基礎教程:enum(枚舉)類型和Option類型enum 和 Option 各自解決一類“語義級”問題:enum 讓“取值只在有限集合內”的約束從注釋變成編譯器強制;Option 讓“值可能不存在”的語義顯式化。enum類型enu…

javaEE-Spring IOCDI

目錄 1、什么是Spring: 2.什么是IoC: 3. 什么是控制反轉呢? 4.IoC容器具備以下優點: 5.DI是什么: 依賴注?方法: 三種注入方法的優缺點: Autowired注解注入存在的問題: Autowired和Resource的區別&#xff…