STM32第十三課:DMA多通道采集光照煙霧

文章目錄

  • 需求
  • 一、DMA(直接存儲器存取)
  • 二、實現流程
    • 1.時鐘使能
    • 2.設置外設寄存器地址
    • 3.設置存儲器地址
    • 4.設置要傳輸的數據量
    • 5.設置通道優先級
    • 6.設置傳輸方向
    • 7.使通道和ADC轉換
  • 三、數據處理
  • 四、需求實現
  • 總結


需求

通過DMA實現光照強度和煙霧濃度的多通道采集


一、DMA(直接存儲器存取)

在這里插入圖片描述
在這里插入圖片描述
作用:
把外設的寄存器里面數據直接傳輸到存儲器中
把存儲器里面數據直接傳輸到外設的寄存器中
把存儲器里面數據直接傳輸到存儲器中
繞開了CPU。

二、實現流程

1、時鐘使能
2、設置外設寄存器地址
3、設置存儲器地址
4、設置要傳輸的數據量
5、設置通道優先級
6、設置傳輸方向:外設到存儲器,還是存儲器到存儲器
循環模式
外設和存儲器的增量模式:外設和存儲器的地址是否向后偏移
外設和存儲器的數據寬度:一個數據的大小(8位,16位,32位)
7、使通道和ADC轉換

1.時鐘使能

DMA有很多通道,本次配置的為DMA1通道
在這里插入圖片描述
可見DMA1在AHB外設時鐘使能寄存器的第0位。

RCC->AHBENR |= 0x1<<0;

2.設置外設寄存器地址

在這里插入圖片描述
由于該ADC1的規則組通道數據寄存器在DR上,所以直接賦給就行。

DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);//設置外設寄存器地址

3.設置存儲器地址

存儲器地址需要自己設置一個變量,我這里為了方便后續取中位數,定義了個結構體數組,存放煙霧和光照兩種變量,每種最多能存放10個。
在這里插入圖片描述

DMA1_Channel1->CMAR = (uint32_t)adcvalue;//設置存儲器地址

結構體及定義

typedef struct{uint16_t light;uint16_t mq2;
}ADCARR;
ADCARR adcvalue[10]={0};

4.設置要傳輸的數據量

在這里插入圖片描述
這個根據需求來設置,想要一次傳多少數據就填多少。
我這里為了獲取每組10個數據,共20個量。
所以這里我填寫的是20。

DMA1_Channel1->CNDTR = 20;//3、設置要傳輸的數據量

5.設置通道優先級

在這里插入圖片描述
在這里插入圖片描述
由于此時就1個通道,所以填那個都無所謂。

DMA1_Channel1->CCR |= 0x3<<12;//4、設置通道優先級   最高

6.設置傳輸方向

外設到存儲器,還是存儲器到存儲器
打開循環模式(循環讀)
外設和存儲器的增量模式:外設和存儲器的地址是否向后偏移
外設和存儲器的數據寬度:一個數據的大小(8位,16位,32位)
全在CCR寄存器上一位一位配就行了

		//5、設置傳輸方向:	//外設到存儲器,還是存儲器到存儲器DMA1_Channel1->CCR &= ~(0x1<<14);//選擇外設和存儲器的之間的傳輸DMA1_Channel1->CCR &= ~(0x1<<4);//從外設讀//外設和存儲器的數據寬度:一個數據的大小(8位,16位,32位)DMA1_Channel1->CCR &= ~(0x3<<10);//存儲器數據寬度DMA1_Channel1->CCR |= 0x1<<10;DMA1_Channel1->CCR &= ~(0x3<<8);//外設寄存器數據寬度DMA1_Channel1->CCR |= 0x1<<8;//外設和存儲器的增量模式:外設和存儲器的地址是否向后偏移DMA1_Channel1->CCR |= 0x1<<7;//存儲器的指針增量打開DMA1_Channel1->CCR &= ~(0x1<<6);//外設的指針增量關閉DMA1_Channel1->CCR |= 0x1<<5;//循環模式打開

7.使通道和ADC轉換

使能一下CRR第0位

	DMA1_Channel1->CCR |= 0x1<<0;

將ADC的掃描和循環開啟,最后開啟ADC1的轉換

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

此時ADC1就會不停轉換,并將光照強度參數和煙霧濃度參數通過DMA從DR寄存器發送到我們定義的變量(存儲器)中。

三、數據處理

為了使獲取的數據更加精準,我定義了一個新的函數用來求光照和煙霧獲取的每10個參數中間的平均數。
代碼如下:

void Get_Smoke_Light_MidValue()
{uint16_t Mid_Light_Value[10]={0};uint16_t Mid_Smoke_Value[10]={0};uint16_t i=0,j=0,temp=0;for(i=0;i<10;i++){Mid_Light_Value[i] = adcvalue[i].light;}for(i=0;i<10;i++){Mid_Smoke_Value[i] = adcvalue[i].mq2;}for(i=0;i<10-1;i++)//光照{for(j=0;j<9-i;j++){if(Mid_Light_Value[j]<Mid_Light_Value[j+1]){temp = Mid_Light_Value[j];Mid_Light_Value[j] = Mid_Light_Value[j+1];Mid_Light_Value[j+1] = temp;}}}temp=0;for(i=0;i<10-1;i++)//煙霧{for(j=0;j<9-i;j++){if(Mid_Smoke_Value[j]<Mid_Smoke_Value[j+1]){temp = Mid_Smoke_Value[j];Mid_Smoke_Value[j] = Mid_Smoke_Value[j+1];Mid_Smoke_Value[j+1] = temp;}}}adcData.light = (Mid_Light_Value[4]+Mid_Light_Value[5])/2;adcData.mq2 = (Mid_Smoke_Value[4]+Mid_Smoke_Value[5])/2;printf("Light = %d\r\n",adcData.light);printf("Smoke = %d\r\n",adcData.mq2);return; 
}

四、需求實現

main.c

#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "string.h"
#include "pwm.h"
#include "adc.h"int main()
{NVIC_SetPriorityGrouping(5);//兩位搶占兩位次級Usart1_Config(); SysTick_Config(72000);RGBpwm_Config();uint8_t cai_count=0;uint16_t cont=0;Adc_Config();while(1){	if(ledcnt[0]>=ledcnt[1]){//過去3sledcnt[0]=0;Get_Smoke_Light_MidValue();}}return 0;
}

adc.c

#include "ADC.h"ADCARR adcvalue[10]={0};
ADCARR adcData={0};//庫函數
void Adc_Config(void)
{//開時鐘ADC1和PC,PARCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); //配置DMARCC->AHBENR |= 0x1<<0;//開啟DMA時鐘DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);//設置外設寄存器地址DMA1_Channel1->CMAR = (uint32_t)adcvalue;//設置存儲器地址DMA1_Channel1->CNDTR = 20;//3、設置要傳輸的數據量DMA1_Channel1->CCR |= 0x3<<12;//4、設置通道優先級   最高//5、設置傳輸方向:	//外設到存儲器,還是存儲器到存儲器DMA1_Channel1->CCR &= ~(0x1<<14);//選擇外設和存儲器的之間的傳輸DMA1_Channel1->CCR &= ~(0x1<<4);//從外設讀//外設和存儲器的數據寬度:一個數據的大小(8位,16位,32位)DMA1_Channel1->CCR &= ~(0x3<<10);//存儲器數據寬度DMA1_Channel1->CCR |= 0x1<<10;DMA1_Channel1->CCR &= ~(0x3<<8);//外設寄存器數據寬度DMA1_Channel1->CCR |= 0x1<<8;//外設和存儲器的增量模式:外設和存儲器的地址是否向后偏移DMA1_Channel1->CCR |= 0x1<<7;//存儲器的指針增量打開DMA1_Channel1->CCR &= ~(0x1<<6);//外設的指針增量關閉DMA1_Channel1->CCR |= 0x1<<5;//循環模式打開//6、使能所使用的通道DMA1_Channel1->CCR |= 0x1<<0;//配置GPIO口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5,光敏GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PC1,煙霧GPIO_Init(GPIOC, &GPIO_InitStructure);//配置ADC1ADC_InitTypeDef ADC_InitStruct={0};  ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC獨立模式ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//數據右對齊ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//選擇軟件SWSTART位觸發ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//連續模式ADC_InitStruct.ADC_ScanConvMode = ENABLE;//開啟掃描ADC_InitStruct.ADC_NbrOfChannel = 2;ADC_Init(ADC1,&ADC_InitStruct);//配置通道ADC_RegularChannelConfig(ADC1, ADC_Channel_5,1, ADC_SampleTime_239Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_11,2, ADC_SampleTime_239Cycles5);	ADC_Cmd(ADC1, ENABLE);ADC1->CR2 |= 0x1<<8;//開啟ADC的DMA請求//校準ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}void Get_Smoke_Light_MidValue()
{uint16_t Mid_Light_Value[10]={0};uint16_t Mid_Smoke_Value[10]={0};uint16_t i=0,j=0,temp=0;for(i=0;i<10;i++){Mid_Light_Value[i] = adcvalue[i].light;}for(i=0;i<10;i++){Mid_Smoke_Value[i] = adcvalue[i].mq2;}for(i=0;i<10-1;i++)//光照{for(j=0;j<9-i;j++){if(Mid_Light_Value[j]<Mid_Light_Value[j+1]){temp = Mid_Light_Value[j];Mid_Light_Value[j] = Mid_Light_Value[j+1];Mid_Light_Value[j+1] = temp;}}}temp=0;for(i=0;i<10-1;i++)//煙霧{for(j=0;j<9-i;j++){if(Mid_Smoke_Value[j]<Mid_Smoke_Value[j+1]){temp = Mid_Smoke_Value[j];Mid_Smoke_Value[j] = Mid_Smoke_Value[j+1];Mid_Smoke_Value[j+1] = temp;}}}adcData.light = (Mid_Light_Value[4]+Mid_Light_Value[5])/2;adcData.mq2 = (Mid_Smoke_Value[4]+Mid_Smoke_Value[5])/2;printf("Light = %d\r\n",adcData.light);printf("Smoke = %d\r\n",adcData.mq2);return; 
}

adc.h

#ifndef _ADC_H_
#define _ADC_H_
#include "stm32f10x.h"
#include "stdio.h"typedef struct{uint16_t light;uint16_t mq2;
}ADCARR;
void Get_Smoke_Light_MidValue();
void Adc_Config(void);
#endif

總結

1.先開時鐘,配置DMA。
2.打開ADC1的兩個通道(煙霧和光照),開啟掃描和循環。
3.使能DMA并開啟ADC轉換。
4.數據處理及主函數調用。

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

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

相關文章

【SkiaSharp繪圖13】SKCanvas方法詳解(二)填充顏色、封裝對象、高性能繪制、點(集)(多段)線、圓角矩形、Surface、沿路徑繪制文字

文章目錄 SKCanvas方法DrawColor 填充顏色DrawDrawable 繪制封裝對象DrawImage 高性能繪制圖像SKBitmap與SKImage對比DrawPicture 繪制圖像SKPicture DrawPoint / DrawPoints 繪制點DrawRoundRect/DrawRoundRectDifference繪制圓角矩形DrawSurface 繪制SurfaceDrawTextOnPath沿…

力扣2055.蠟燭之間的盤子

力扣2055.蠟燭之間的盤子 預處理每個元素左右最近的蠟燭下標 同時求前綴和遍歷每個詢問找到左右端點對應的內部的最近蠟燭(最大區間) class Solution {public:vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {vector<…

List接口, ArrayList Vector LinkedList

Collection接口的子接口 子類Vector&#xff0c;ArrayList&#xff0c;LinkedList 1.元素的添加順序和取出順序一致&#xff0c;且可重復 2.每個元素都有其對應的順序索引 方法 在index 1 的位置插入一個對象&#xff0c;list.add(1,list2)獲取指定index位置的元素&#…

sheng的學習筆記-AI-聚類(Clustering)

ai目錄 sheng的學習筆記-AI目錄-CSDN博客 基礎知識 什么是聚類 在“無監督學習”(unsupervised learning)中&#xff0c;訓練樣本的標記信息是未知的&#xff0c;目標是通過對無標記訓練樣本的學習來揭示數據的內在性質及規律&#xff0c;為進一步的數據分析提供基礎。此類學…

Android跨進程通信,binder傳輸數據過大導致客戶端APP,Crash,異常捕獲,監聽異常的數值臨界值,提前Hook攔截。

文章目錄 Android跨進程通信&#xff0c;binder傳輸數據過大導致Crash&#xff0c;異常捕獲&#xff0c;監聽異常的數值臨界值&#xff0c;提前Hook攔截。1.binder在做跨進程傳輸時&#xff0c;最大可以攜帶多少數據1.1有時候這個1m的崩潰系統捕獲不到異常&#xff0c; 2.監測異…

志愿填報指南:為什么我強烈建議你報考計算機專業

首先恭喜2024屆高考的同學們&#xff0c;你們已經通過了高考的考驗&#xff0c;即將進入人生的新階段——大學。 現在正是高考完填報志愿的時刻&#xff0c;Left聽到身邊朋友提到報考志愿的諸多問題&#xff1a; 志愿填報怎么填&#xff1f;我要報考什么專業&#xff1f;這個…

[Cloud Networking] OSPF

OSPF 開放式最短路徑優先&#xff08;Open Shortest Path First&#xff09;是一種動態路由協議&#xff0c;它屬于鏈路狀態路由協議&#xff0c;具有路由變化收斂速度快、無路由環路、支持變長子網掩碼和匯總、層次區域劃分等優點。 1 OSPF Area 為了適應大型網絡&#xff0…

可編程定時計數器8253/8254 - 8253入門

時鐘-給設備打拍子 概述 在計算機系統中&#xff0c;為了使所有設備之間的通信井然有序&#xff0c;各通信設備間必須有統一的節奏&#xff0c;不能各干各的&#xff0c;這個節奏就被稱為定時或時鐘 時鐘并不是計算機處理速度的衡量&#xff0c;而是一種使設備間相互配合而避…

【2024-06-21】網易互娛秋招實習筆試三道編程題解

恭喜發現寶藏!搜索公眾號【TechGuide】回復公司名,解鎖更多新鮮好文和互聯網大廠的筆經面經。 作者@TechGuide【全網同名】 訂閱專欄: 【專享版】2024最新大廠筆試真題解析,錯過必后悔的寶藏資源! 第一題:陰陽師斗技 題目描述 小蓋正在參加陰陽師的斗技。已知斗技的規…

Linux 磁盤掛載與分區

Linux 磁盤掛載與分區 vda1: 其中vd表示虛擬磁盤&#xff0c;a表示第一塊磁盤&#xff0c;b表示第二塊磁盤&#xff0c;1表示第一塊磁盤的第一分區&#xff08;顯然兩塊磁盤都只有一個分區&#xff09;圖中可以看到&#xff0c;vda1磁盤只有一個分區&#xff0c;且全部掛載到根…

vue3使用vant4的列表vant-list點擊進入詳情自動滾動到對應位置,踩坑日記(一天半的踩坑經歷)

1.路由添加keepAlive <!-- Vue3緩存組件&#xff0c;寫法和Vue2不一樣--><router-view v-slot"{ Component }"><keep-alive><component :is"Component" v-if"$route.meta.keepAlive"/></keep-alive><component…

如何在MySQL中按字符串中的數字排序

在管理數據庫時&#xff0c;我們經常遇到需要按嵌入在字符串中的數字進行排序的情況。這在實際應用中尤為常見&#xff0c;比如文件名、代碼版本號等字段中通常包含數字&#xff0c;而這些數字往往是排序的關鍵。本文將詳細介紹如何在MySQL中利用正則表達式提取字符串中的數字并…

LiteDB - 一個單數據文件 .NET NoSQL 文檔存儲

LiteDB 一個小巧、快速、輕量級的 NoSQL 嵌入式數據庫。 Serverless NoSQL 文檔存儲類似于 MongoDB 的簡單 API100% C# 代碼,支持 .NET 3.5 / .NET 4.0 / NETStandard 1.3 / NETStandard 2.0,單 DLL (小于 300 kb)支持線程和進程安全支持文檔/操作級別的 ACID支持寫失敗后的數…

Google 發布最新開放大語言模型 Gemma 2,現已登陸 Hugging Face Hub

Google 發布了最新的開放大語言模型 Gemma 2&#xff0c;我們非常高興與 Google 合作&#xff0c;確保其在 Hugging Face 生態系統中的最佳集成。你可以在 Hub 上找到 4 個開源模型 (2 個基礎模型和 2 個微調模型) 。發布的功能和集成包括&#xff1a; Hub 上的模型https://hf.…

Java家教系統小程序APP公眾號h5源碼

讓學習更高效&#xff0c;更便捷 &#x1f31f; 引言&#xff1a;家教新選擇&#xff0c;小程序來助力 在快節奏的現代生活中&#xff0c;家長們越來越注重孩子的教育問題。然而&#xff0c;如何為孩子找到一位合適的家教老師&#xff0c;成為了許多家長頭疼的問題。現在&…

交叉編譯中的 --build、 --host和 --target

在交叉編譯中比較常見的一些參數就是build、host和target了,正確的理解這三者的含義對于交叉編譯是非常重要的,下面就此進行解釋   --build=編譯該軟件所使用的平臺   --host=該軟件將運行在哪個平臺   --target=該軟件所處理的目標平臺 我們經常會看到如下代碼:   …

谷歌個人號,20人連續封測14天所需設備該怎么解決?

現在&#xff0c;在Google Play上架應用&#xff0c;對于大部分開發者來說&#xff0c;真的是不小的挑戰&#xff0c;因為目前谷歌上架政策越來越嚴格了。特別是從2023年11月13日起&#xff0c;新政策要求個人開發者賬號的應用必須經過20個獨立用戶連續14天的封閉測試&#xff…

【C語言】--分支和循環(1)

&#x1f37f;個人主頁: 起名字真南 &#x1f9c7;個人專欄:【數據結構初階】 【C語言】 目錄 前言1 if 語句1.1 if1.2 else1.3 嵌套if1.4 懸空else 前言 C語言是結構化的程序設計語言&#xff0c;這里的結構指的是順序結構、選擇結構、循環結構。 我們可以用if、switch實現分支…

vue2實例實現一個初步的vuex

vue2實例實現一個初步的vuex 實現源碼&#xff1a;vue2-review 1.App.vue 2.store目錄下的index.js 3.效果 微信公眾號&#xff1a;刺頭拾年

MATLAB的.m文件與Python的.py文件:比較與互參

simulink MATLAB的.m文件與Python的.py文件&#xff1a;比較與互參相似之處**1. 基本結構****2. 執行邏輯****3. 可讀性和維護性** 差異性**1. 語法特性****2. 性能和應用****3. 開發環境** 互相學習的可能性結論 MATLAB的.m文件與Python的.py文件&#xff1a;比較與互參 在編…