打印
[STM32F1]

【转】基于stm32f103zet6的DMA学习

[复制链接]
792|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
焚琴煮鹤|  楼主 | 2016-11-12 23:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
stm32内部集成的ADC介绍
一、参考电压的范围为
/*2.4V≦ V ≦3.6V
所以它的输入模拟电压范围0 <= V <=V*/
二、需要测量负电压或测量的电压信号超出范围时,要先经过运算电路进行平移或利用电阻分压。
三、我采用的是51单片机上面的10k的电阻来模拟输入
四、规则通道和注入通道
/*所谓规则,那么就是按常理出牌的,我们可以称之为正常的通道,那么与之对应的是注入通道,就是
在规则通道正在转换的时候是可以被注入通道打断,转而去执行注入通道转换的,当注入通道转换完
成之后,才继续去进行规则通道里面的转换,TM32ADC的规则通道组最多包含16 个转换,而注入通道
组最多包含 4 个通道*/
五、初始化ADC这是必须的,比东有一个结构体来初始化这个ADC
1、首先确定从哪里输入我们的模拟量呢?
这里涉及到ADC通道的知识,每个ADC通道都对应着一个GPIO引脚端口
PC0对应的默认复用功能是ADC1、ADC2、ADC3的通道10
所以最开始应该配置GPIO,现在可以来做个猜测
2、配置GPIO


GPIO_Mode = GPIO_Mode_AIN
GPIO_Pin = GPIO_Pin_10
GPIO_Speed = GPIO_Speed_50MHz   
以上就是模拟输入
六、然后是配置ADC,也就是初始化ADC了,
找到这样一个结构体
ADC_InitTypeDef
结构体成员有{
FunctionalState  ADC_ContinuousConvMode
uint32_t  ADC_DataAlign
uint32_t  ADC_ExternalTrigConv
uint32_t  ADC_Mode
uint8_t  ADC_NbrOfChannel
FunctionalState  ADC_ScanConvMode
}
1、ADC_ContinuousConvMode的取值有
Specifies whether the conversion is performed in Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE
此参数用来配置是否开启循环采集ENABLE or DISABLE
2、ADC_DataAlign明显意思是数据对齐,它的取值有
#define  ADC_DataAlign_Left   ((uint32_t)0x00000800)
#define  ADC_DataAlign_Right   ((uint32_t)0x00000000)
#define  IS_ADC_DATA_ALIGN(ALIGN)
左对齐,右对齐。。
3、ADC_ExternalTrigConv外部中断触发方式?它的取值有
#define  ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO   ((uint32_t)0x000C0000)
#define  ADC_ExternalTrigConv_None   ((uint32_t)0x000E0000)
#define  ADC_ExternalTrigConv_T1_CC1   ((uint32_t)0x00000000)
#define  ADC_ExternalTrigConv_T1_CC2   ((uint32_t)0x00020000)
#define  ADC_ExternalTrigConv_T1_CC3   ((uint32_t)0x00040000)
#define  ADC_ExternalTrigConv_T2_CC2   ((uint32_t)0x00060000)
#define  ADC_ExternalTrigConv_T2_CC3   ((uint32_t)0x00020000)
#define  ADC_ExternalTrigConv_T3_CC1   ((uint32_t)0x00000000)
#define  ADC_ExternalTrigConv_T3_TRGO   ((uint32_t)0x00080000)
#define  ADC_ExternalTrigConv_T4_CC4   ((uint32_t)0x000A0000)
#define  ADC_ExternalTrigConv_T5_CC1   ((uint32_t)0x000A0000)
#define  ADC_ExternalTrigConv_T5_CC3   ((uint32_t)0x000C0000)
#define  ADC_ExternalTrigConv_T8_CC1   ((uint32_t)0x00060000)
#define  ADC_ExternalTrigConv_T8_TRGO   ((uint32_t)0x00080000)
触发方式很丰富,当然 ADC_ExternalTrigConv_None这就表示不采用外部中断方式触发(那么软件触发)
4、ADC_Mode ADC的模式?
Configures the ADC to operate in independent or dual mode.
This parameter can be a value of ADC_mode
它的取值有
#define  ADC_Mode_AlterTrig   ((uint32_t)0x00090000)
#define  ADC_Mode_FastInterl   ((uint32_t)0x00070000)
#define  ADC_Mode_Independent   ((uint32_t)0x00000000)
#define  ADC_Mode_InjecSimult   ((uint32_t)0x00050000)
#define  ADC_Mode_InjecSimult_FastInterl   ((uint32_t)0x00030000)
#define  ADC_Mode_InjecSimult_SlowInterl   ((uint32_t)0x00040000)
#define  ADC_Mode_RegInjecSimult   ((uint32_t)0x00010000)
#define  ADC_Mode_RegSimult   ((uint32_t)0x00060000)
#define  ADC_Mode_RegSimult_AlterTrig   ((uint32_t)0x00020000)
#define  ADC_Mode_SlowInterl   ((uint32_t)0x00080000)
貌似是有注入组、和规则组的概念,有些单词不是很熟悉,没关系那就先这样吧!用到了再来
5、ADC_NbrOfChannel采样通道?
明显一般采用的是是16个规则通道,那取值就是1--16
Specifies the number of ADC channels that will be converted using the sequencer for regular
channel group.This parameter must range from 1 to 16
6、ADC_ScanConvMode,字面意思不是很懂,看手册
Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel)
mode. This parameter can be set to ENABLE or DISABLE
意思是当有多个通道的时候,使用扫描的方式,反之只有单个通道的是那么就是选择单通道了
那么取值就是ENABLE or DISABLE
至此结构成员分析完毕,下面来猜测一下,应该怎样赋值,声明:单通道采集,右对齐(方便存数据)
沙发
焚琴煮鹤|  楼主 | 2016-11-13 00:02 | 只看该作者
软件触发,通道采用10(使用PC0)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None
ADC_InitStructure.ADC_Mode= ADC_Mode_Independent
ADC_InitStructure.ADC_NbrOfChannel = 11
ADC_InitStructure.ADC_ScanConvMode = DISABLE
下面来对照下,原始代码看看:
  /* ADC1 configuration */
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);
显然错误还是比较多的,没关系,慢慢分析
1、因为是一个通道没必要扫描,所以第2个错了
2、通道数目理解错误。我以为那是指定的哪个通道,原来是number of channel
3、好的最后就是少了一个库函数的调用,这确实是缺乏这种意识呀!
七、既然是使用DMA来传送数据,那么下一步就开始初始化DMA吧!DMA的知识暂时不分析,那个得单独出来
我还是先来了解下DMA的变成思想吧!
1、STM32就是这样完美,每个模块都能有个结构体来组织它的一些参数配置,我甚至觉得它和uboot一样讨人喜欢
这只是我的愚见,也是这样一个结构体 DMA_InitTypeDef DMA_InitStructure;
跟着手册来吧
2、DMA_InitTypeDef{
uint32_t  DMA_BufferSize
uint32_t  DMA_DIR
uint32_t  DMA_M2M
uint32_t  DMA_MemoryBaseAddr
uint32_t  DMA_MemoryDataSize
uint32_t  DMA_MemoryInc
uint32_t  DMA_Mode
uint32_t  DMA_PeripheralBaseAddr
uint32_t  DMA_PeripheralDataSize
uint32_t  DMA_PeripheralInc
uint32_t  DMA_Priority
}
3、DMA_BufferSize,明显就是数据的大小,看她是怎么描述的
Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to
the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in
the transfer direction
可以得出DMA_PeripheralDataSize = DMA_MemoryDataSize = DMA_BufferSize
取值可以是
#define  DMA_MemoryDataSize_Byte   ((uint32_t)0x00000000)
#define  DMA_MemoryDataSize_HalfWord   ((uint32_t)0x00000400)
#define  DMA_MemoryDataSize_Word   ((uint32_t)0x00000800)
4、DMA_DIR字面意思不怎么明朗方向?看解释
Specifies if the peripheral is the source or destination. This parameter can be a value of
DMA_data_transfer_direction
数据源和目的源
取值
#define  DMA_DIR_PeripheralDST   ((uint32_t)0x00000010)
#define  DMA_DIR_PeripheralSRC   ((uint32_t)0x00000000
从存储器到外设或者从外设到存储器
5、DMA_M2M 这个可以猜测到,DMA的作用出了上面一个还有M to M的没有提及那么
#define  DMA_M2M_Disable   ((uint32_t)0x00000000)
#define  DMA_M2M_Enable   ((uint32_t)0x00004000)
可以这样设置了
6、DMA_MemoryBaseAddr、DMA_PeripheralBaseAddr
这两个可以一起看了,字面意思很清楚了,外设地址和存储器(变量)地址,这个得看你的地址了
7、DMA_MemoryInc、DMA_PeripheralInc看变量名不是很了解,中断触发么?看解释
Specifies whether the memory address register is incremented(adj.增加的) or not.
This parameter can be a value of DMA_memory_incremented_mode
地址增加?理解严重错误,那么就是地址递增的意思吧,那就是可以连续采集多个通道咯?继续分析
8、DMA_Mode:DMA的模式,他有什么模式呢?看解释
Specifies the operation mode of the DMAy Channelx.
This parameter can be a value of DMA_circular_normal_mode
还有一句:The circular buffer mode cannot be used if the memory-to-memory
data transfer is configured on the selected Channel
取值有
#define  DMA_Mode_Circular   ((uint32_t)0x00000020)
#define  DMA_Mode_Normal   ((uint32_t)0x00000000)
正常和循环模式,难道是轮采?先这样继续
9、DMA_Priority优先级这个就好理解了,不就是控制优先权么看解释以及取值
Specifies the software priority for the DMAy Channelx. This parameter can be
a value of DMA_priority_level
取值
#define  DMA_Priority_High   ((uint32_t)0x00002000)
#define  DMA_Priority_Low   ((uint32_t)0x00000000)
#define  DMA_Priority_Medium   ((uint32_t)0x00001000)
#define  DMA_Priority_VeryHigh   ((uint32_t)0x00003000
很明朗4个优先级
至此,分析完毕,尝试性猜测

使用特权

评论回复
板凳
焚琴煮鹤|  楼主 | 2016-11-13 00:05 | 只看该作者
1、DMA_InitStructure.DMA_BufferSize = 1
2、DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST
3、DMA_InitStructure.DMA_M2M = DMA_M2M_Disable
4、DMA_InitStructure.DMA_MemoryBaseAddr = 一个地址单元的变量单字节 可以使char型的
5、DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte
6、DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable 不需要地址增量
7、DMA_InitStructure.DMA_Mode = DMA_Mode_Circular 不停的采
8、DMA_InitStructure.DMA_PeripheralBaseAddr = 串口的地址?
9、DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte
10、DMA_InitStructure.MA_PeripheralInc = DMA_PeripheralInc_Disable 同样的
11、DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh 给最高的
查看源代码
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
貌似有点不妙的感觉
1、MA_InitStructure.DMA_DIR这个明显是作为数据源
2、DMA_MemoryDataSize_Byte和DMA_PeripheralDataSize_HalfWord有什么区别
百度里面我没有找到,先这样,等做完实验再验证
八、结构体成员初始化完毕之后,还有很多工作要做
1、  /* ADC1 regular channel11 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
  配置规则通道11
2、  /* Enable DMA channel1 */
  DMA_Cmd(DMA1_Channe10, ENABLE);
  使能DMA通道
3、  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
  使能ADC1的DMA控制器
4、  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  使能ADC1
5、  /* Enable ADC1 reset calibaration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));//复位校准


  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));//校准
     
  /* Start ADC1 Software Conversion */
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发,这时候真正开始转换  
  硬件测试后,结果正确的!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

106

帖子

3

粉丝