如何构建一块电路板的护城河1_ADC的DMA读取和处理

如何构建一块电路板的护城河1_ADC的DMA读取和处理

STM32 编程

通过MXCUBE可以设置的参数如下:


MXCUBE生成界面.png

初始化函数如下:

 hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;     //ADC的频率不建议太高
  hadc1.Init.Resolution = ADC_RESOLUTION_12B; //精度
  hadc1.Init.ScanConvMode = ENABLE; //使能,则是顺序转换模式,不再有插队情况
  hadc1.Init.ContinuousConvMode = ENABLE; //连续转换,否则只转换一次
  hadc1.Init.DiscontinuousConvMode = DISABLE; //连续转换,当然就不间断了
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//外部触发的边沿,这里NONE
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; //不需要外部触发
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;  //低位对齐
  hadc1.Init.NbrOfConversion = 8;  //8个通道
  hadc1.Init.DMAContinuousRequests = ENABLE; //连续不断写入DMA
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; 

ADC进行初始化以后,在MSP中会对开辟的DMA进行初始化,如下:

 hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_adc1.Init.MemDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

在下面会有一条,将DMA和ADC连接起来。

__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);

这样,将ADC1采样得到的数据,会自动的保存到dma的内存中。

MX还有一个任务,就是中断设置,如下:

{
  HAL_ADC_IRQHandler(&hadc1);
}
    HAL_DMA_IRQHandler(&hdma_adc1);

所以实际上,我们没有进行中断的处理,在初始化函数中,调用

uint32_t ADC_ConvertedValue[ADC_NUMOFCHANNEL];
……
HAL_ADC_Start_DMA(&hadc1,ADC_ConvertedValue,ADC_NUMOFCHANNEL);  

这样,当ADC8个通道的值采集完成以后,自动会交给DMA,而DMA直接将数据保存到ADC_ConvertedValue中。其中ADC_ConvertedValue是DMA设置的数据宽度,一个8个通道的值。

我们先定义一个数据结构体,用来保存从数组中读出来的中间值,并不是和DMA通道物理对应,如下:

typedef struct
{
  int32_t motor2_U_current;
  int32_t motor2_V_current;
  int32_t motor2_W_current;
  int32_t motor1_U_current;
  int32_t motor1_V_current;
  int32_t motor1_W_current;
  int32_t bus_volt;
  int32_t controller_temp;
}DMA_AD_VALUE;

并在头文件中申明一下结构体:并在C文件中进行定义

extern DMA_AD_VALUE dma_ad;
DMA_AD_VALUE dma_ad;

同时我们设置一个结构体,用来保存一些中间变量,如下:

typedef struct {
         int32_t   BUS_Curr ;     // DC Bus  Current
         int32_t   PhaseU_Curr;   // Phase A Current
         int32_t   PhaseV_Curr;   // Phase A Current
         int32_t   BUS_Voltage ;  //DC Bus  Voltage      
         int32_t   RP_speed_Voltage ;     //  RP1_Voltage
         int32_t   OffsetBUS_Curr ;     // DC Bus  Current
         int32_t   OffsetPhaseU_Curr;   // Phase A Current
         int32_t   OffsetPhaseV_Curr;   // Phase A Current
         int32_t   Coeff_filterK1;   // Phase A Current
           int32_t   Coeff_filterK2;   // Phase A Current 
       }ADCSamp;
#define  ADCSamp_DEFAULTS  {0,0,0,0,0,0,0,0,268,756}

有两个电机,所以我们申明和定义一个结构体变量如下:

extern ADCSamp      ADCSampPareM1;  // M1 refer to tim8
extern ADCSamp      ADCSampPareM2;  // M2 refer to tim1

ADCSamp      ADCSampPareM1=ADCSamp_DEFAULTS;
ADCSamp      ADCSampPareM2=ADCSamp_DEFAULTS;

首先,我们要读取所有模拟值的初始化值,初始化我们通过连续读取32次求平均值来获得,如下:

//校准作用,电流传感器的偏移值为1.65V
void Offset_CurrentReading(void)
{
    static uint8_t i;  

  /* ADC Channel used for current reading are read  in order to get zero currents ADC values*/
  //32次采样求平均值,电流传感器初始校准 
 memset((uint8_t*)(&ADCSampPareM1),0,sizeof(ADCSampPareM1));
 memset((uint8_t*)(&ADCSampPareM2),0,sizeof(ADCSampPareM2));
for(i=32; i!=0; i--)   
  {

    ADCSampPareM1.OffsetBUS_Curr += ADC_ConvertedValue[6]; //通道6,总线电流
    ADCSampPareM1.OffsetPhaseV_Curr += ADC_ConvertedValue[4];//电机M1 V相电流
    ADCSampPareM1.OffsetPhaseU_Curr += ADC_ConvertedValue[5];

    ADCSampPareM2.OffsetBUS_Curr += ADC_ConvertedValue[7];
    ADCSampPareM2.OffsetPhaseU_Curr += ADC_ConvertedValue[3];
    ADCSampPareM2.OffsetPhaseV_Curr += ADC_ConvertedValue[0];
    Delay(10000);
    Delay(10000);
  }
    ADCSampPareM1.OffsetBUS_Curr = ADCSampPareM1.OffsetBUS_Curr>>5; //除以2^5,获得平均数
    ADCSampPareM1.OffsetPhaseV_Curr= ADCSampPareM1.OffsetPhaseV_Curr>>5; 
    ADCSampPareM1.OffsetPhaseU_Curr=ADCSampPareM1.OffsetPhaseU_Curr>>5;
    ADCSampPareM2.OffsetBUS_Curr = ADCSampPareM2.OffsetBUS_Curr>>5;
    ADCSampPareM2.OffsetPhaseV_Curr= ADCSampPareM2.OffsetPhaseV_Curr>>5; 
    ADCSampPareM2.OffsetPhaseU_Curr=ADCSampPareM2.OffsetPhaseU_Curr>>5;
}

有了上面的数组,我们可以通过如下的两个函数计算电机相线的电流值

void   ADC_Sample_M1(void )
{  
    ADCSampPareM1.PhaseV_Curr=((ADC_ConvertedValue[4]-ADCSampPareM1.OffsetPhaseV_Curr)<<2);     
    ADCSampPareM1.PhaseU_Curr=((ADC_ConvertedValue[5]-ADCSampPareM1.OffsetPhaseU_Curr)<<2);
}

void   ADC_Sample_M2(void )
{
    ADCSampPareM2.PhaseV_Curr=((ADC_ConvertedValue[0]-ADCSampPareM2.OffsetPhaseV_Curr)<<2);     
    ADCSampPareM2.PhaseU_Curr=((ADC_ConvertedValue[3]-ADCSampPareM2.OffsetPhaseU_Curr)<<2);
}

然后调用clark变换和PARK变换,用来做SVPWM计算

        ADC_Sample_M2( );

        ClarkeI_M2.As=ADCSampPareM2.PhaseU_Curr;
        ClarkeI_M2.Bs=ADCSampPareM2.PhaseV_Curr;

然后通过下面的计算,获得总线的电流值和温度值,代码定义在AD_period_task中,在user_period_task中被周期性的读取。而电机的电流值读取频率为18KHZ,频率比总线电流和温度的频率要快很多。

  ADCSampPareM1.BUS_Curr  =  ADC_ConvertedValue[6]-ADCSampPareM1.OffsetBUS_Curr;
  ADCSampPareM2.BUS_Curr  =  ADC_ConvertedValue[7]-ADCSampPareM2.OffsetBUS_Curr;        
  dma_ad.bus_volt = VOLT_TO_BUS_VOLT(CAL_ADCDMA_fifo_AVGRPM(AD_DMA_CH3,2)); 
//  tempRIS_value = VOLT_TO_RISITOR(CAL_ADCDMA_fifo_AVGRPM(AD_DMA_CH2,1));  
  temp_ad100v = CAL_ADCDMA_fifo_AVGRPM(AD_DMA_CH2,1);
  temp_ad100v = adva_to_100v(temp_ad100v);
  tempRIS_value = VOLT_TO_RISI(temp_ad100v);

[
image

markdownFile.md
6.7 KB](https://app.yinxiang.com/shard/s51/res/2a638deb-9348-419d-aa4b-38fe1b2851a5/markdownFile.md)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容