stm32cube中文教程:操作24c02程序,调用I2C可直接写数据,完整代码

软件教程admin 发表了文章 • 28 个评论 • 4669 次浏览 • 2014-10-14 00:10 • 来自相关话题

以前用stm32cubemx生成的代码写I2C的24c02很麻烦,因为自动生成的代码时对分页操作的
分页操作又没有弄对数据地址自动分页的代码,于是,手动分页写数据,安排数据地址。
坑死了。
研究了下,自己写了几个函数省去以上的麻烦。
方法很简单,前面的帖子里面我也提到了代码。
将要写的数据按照一个字节一个字节的方法写入就绝对不存在分页问题,而且读取操作页不存在分页问题,好了,完整代码如下:
文件:24C02.C内容


/[i] Includes ------------------------------------------------------------------[/i]/
#include "24C02.h"
#include "stdio.h"
__IO uint32_t I2CTimeout = I2C_Open_LONG_TIMEOUT;

static void I2C_delay(uint16_t cnt);

/*******************************************************************************
* Function Name : I2C_delay
* Description :
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
static void I2C_delay(uint16_t cnt)
{
while(cnt--);
}
/*******************************************************************************
* Function Name : I2C_Read
* Description :
* Input :
* Output :
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_Read(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num)
{
uint8_t err=0;
while(HAL_I2C_Mem_Read (I2Cx ,I2C_Addr,addr,I2C_MEMADD_SIZE_8BIT,buf,num,I2CTimeout) != HAL_OK ){};

//err = HAL_I2C_Mem_Read(I2Cx, I2C_Addr, addr, I2C_MEMADD_SIZE_8BIT, buf, num, I2CTimeout);
if(err)
return err;
else
return 0;
}

/*******************************************************************************
* Function Name : I2C_WriteOneByte
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_WriteOneByte(I2C_HandleTypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t value)
{
// uint8_t err=0;

while( HAL_I2C_Mem_Write(I2Cx, I2C_Addr, addr, I2C_MEMADD_SIZE_8BIT, &value, 0x01, I2CTimeout) != HAL_OK ){};
//I2C_delay(50000);
// if(err)
// return 1;
// else
// return 0;
}

学习 stm32cubemx软件编程,来STM32CUBE.COM ,随时更新!
/*******************************************************************************
* Function Name : I2C_Write
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_Write(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num)
{
uint8_t err=0;

while(num--)
{
I2C_WriteOneByte(I2Cx, I2C_Addr,addr++,*buf++);
// if(I2C_WriteOneByte(I2Cx, I2C_Addr,addr++,*buf++))
// {
// err++;
// }
}
// if(err)
// return 1;
// else
// return 0;
}

/*********************************************************************************************************
END FILE
*********************************************************************************************************/

文件24C02.H内容:


#ifndef __24C02_H
#define __24C02_H

/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private define ------------------------------------------------------------[/i]/
#define AT24C01A
//#define AT24C01

#define ADDR_24LC02 0xA0
#define I2C_PAGESIZE 4


/* Maximum Timeout values for flags and events waiting loops. These timeouts are
not based on accurate values, they just guarantee that the application will
not remain stuck if the I2C communication is corrupted.
You may modify these timeout values depending on CPU frequency and application
conditions (interrupts routines ...). */
#define I2C_Open_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2C_Open_LONG_TIMEOUT ((uint32_t)0xffff)

/[i] Private function prototypes -----------------------------------------------[/i]/
uint8_t I2C_Read(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num);
uint8_t I2C_Write(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num);

#endif

/*********************************************************************************************************
END FILE
*********************************************************************************************************/


代码就那么多。
下面介绍下用法:
首先main文件肯定要调用


#include "24c02.h"
#include "stdio.h"
#include "string.h"


到了该写数据的地方,直接调用上面的函数,如下:


I2C_Write(&hi2c2,ADDR_24LC02,0x05,(uint8_t *)WriteBuffer,sizeof(WriteBuffer) );


我用的是stm32cube中的I2C2口,而ADDR_24LC02前面的函数H文件中已经有了,从地质0x05
开始写入,写入的是WriteBuffer这个结构表数据,里面包含了sizeof(WriteBuffer) 这么多个数据,读取的时候用


I2C_Read(&hi2c2,ADDR_24LC02,0x05,(uint8_t *)ReadBuffer,sizeof(WriteBuffer) )


同上,读取数据到ReadBuffer这个结构表中。嗯,以上结束。
有问题可以留言。
原创转载请注明。
所有本站实验过的程序都可以到【资源下载】网盘里找到........... 查看全部
以前用stm32cubemx生成的代码写I2C的24c02很麻烦,因为自动生成的代码时对分页操作的
分页操作又没有弄对数据地址自动分页的代码,于是,手动分页写数据,安排数据地址。
坑死了。
研究了下,自己写了几个函数省去以上的麻烦。
方法很简单,前面的帖子里面我也提到了代码。
将要写的数据按照一个字节一个字节的方法写入就绝对不存在分页问题,而且读取操作页不存在分页问题,好了,完整代码如下:
文件:24C02.C内容


/[i] Includes ------------------------------------------------------------------[/i]/
#include "24C02.h"
#include "stdio.h"
__IO uint32_t I2CTimeout = I2C_Open_LONG_TIMEOUT;

static void I2C_delay(uint16_t cnt);

/*******************************************************************************
* Function Name : I2C_delay
* Description :
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
static void I2C_delay(uint16_t cnt)
{
while(cnt--);
}
/*******************************************************************************
* Function Name : I2C_Read
* Description :
* Input :
* Output :
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_Read(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num)
{
uint8_t err=0;
while(HAL_I2C_Mem_Read (I2Cx ,I2C_Addr,addr,I2C_MEMADD_SIZE_8BIT,buf,num,I2CTimeout) != HAL_OK ){};

//err = HAL_I2C_Mem_Read(I2Cx, I2C_Addr, addr, I2C_MEMADD_SIZE_8BIT, buf, num, I2CTimeout);
if(err)
return err;
else
return 0;
}

/*******************************************************************************
* Function Name : I2C_WriteOneByte
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_WriteOneByte(I2C_HandleTypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t value)
{
// uint8_t err=0;

while( HAL_I2C_Mem_Write(I2Cx, I2C_Addr, addr, I2C_MEMADD_SIZE_8BIT, &value, 0x01, I2CTimeout) != HAL_OK ){};
//I2C_delay(50000);
// if(err)
// return 1;
// else
// return 0;
}

学习 stm32cubemx软件编程,来STM32CUBE.COM ,随时更新!
/*******************************************************************************
* Function Name : I2C_Write
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_Write(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num)
{
uint8_t err=0;

while(num--)
{
I2C_WriteOneByte(I2Cx, I2C_Addr,addr++,*buf++);
// if(I2C_WriteOneByte(I2Cx, I2C_Addr,addr++,*buf++))
// {
// err++;
// }
}
// if(err)
// return 1;
// else
// return 0;
}

/*********************************************************************************************************
END FILE
*********************************************************************************************************/

文件24C02.H内容:


#ifndef __24C02_H
#define __24C02_H

/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private define ------------------------------------------------------------[/i]/
#define AT24C01A
//#define AT24C01

#define ADDR_24LC02 0xA0
#define I2C_PAGESIZE 4


/* Maximum Timeout values for flags and events waiting loops. These timeouts are
not based on accurate values, they just guarantee that the application will
not remain stuck if the I2C communication is corrupted.
You may modify these timeout values depending on CPU frequency and application
conditions (interrupts routines ...). */
#define I2C_Open_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2C_Open_LONG_TIMEOUT ((uint32_t)0xffff)

/[i] Private function prototypes -----------------------------------------------[/i]/
uint8_t I2C_Read(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num);
uint8_t I2C_Write(I2C_HandleTypeDef [i]I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t [/i]buf,uint16_t num);

#endif

/*********************************************************************************************************
END FILE
*********************************************************************************************************/


代码就那么多。
下面介绍下用法:
首先main文件肯定要调用


#include "24c02.h"
#include "stdio.h"
#include "string.h"


到了该写数据的地方,直接调用上面的函数,如下:


I2C_Write(&hi2c2,ADDR_24LC02,0x05,(uint8_t *)WriteBuffer,sizeof(WriteBuffer) );


我用的是stm32cube中的I2C2口,而ADDR_24LC02前面的函数H文件中已经有了,从地质0x05
开始写入,写入的是WriteBuffer这个结构表数据,里面包含了sizeof(WriteBuffer) 这么多个数据,读取的时候用


I2C_Read(&hi2c2,ADDR_24LC02,0x05,(uint8_t *)ReadBuffer,sizeof(WriteBuffer) )


同上,读取数据到ReadBuffer这个结构表中。嗯,以上结束。
有问题可以留言。
原创转载请注明。
所有本站实验过的程序都可以到【资源下载】网盘里找到...........

stm32的定时器time的slave mode模式详细介绍(转载)

经验分享admin 发表了文章 • 0 个评论 • 3019 次浏览 • 2014-10-14 00:06 • 来自相关话题

STM32的每个定时器都可以由另一个定时器触发启动

定时器一般是通过软件设置而启动,STM32的每个定时器也可以通过外部信号触发而启动,还可以通过另外一个定时器的某一个条件被触发而启动。这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件。

这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式。

STM32定时器输出比较模式中的疑

OCx与OCxREF和CCxP之间的关系
初学STM32,我这个地方卡了很久,现在终于有些明白了,现在把我的理解写下与大家共享,如果有不对的地方,还请指出。
OCxREF就是一个参考信号,并且约定:
OCxREF=1,称OCxREF有效。反之,OCxREF=0,称OCxREF无效;
‘1’电平(高电平)称为OCxREF的有效电平,‘0’ 电平(低电平)称为OCxREF的无效电平。
——依据参考手册:The output stage generates an intermediate waveform which is then used for reference:OCxRef (active high). The polarity acts at the end of the chain.
(翻译)输出阶段产生一个中间波形OCxRef(高有效)作为参考。输出信号的极性体现在信号链的末端。
现在解释几个名词之间的关系:
STM32定时器输出比较模式中的疑惑
然后来理解输出比较的几个模式(PWM模式是输出比较模式的特例)
查看TIMx_CCMR1寄存器的OC1M域,有如下定义(摘自最新版的参考手册)
STM32定时器输出比较模式中的疑惑
翻译如下:
000:冻结——输出比较寄存器TIMx_CCR1中的内容与计数器TIMx_CNT中的内容之间的比较对输出无影响。(此模式用于时基的生成)
001:当匹配时,设置通道1为有效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉高OC1REF 信号。
010:当匹配时,设置通道1为无效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉低OC1REF 信号。
011:翻转——当TIMx_CNT= TIMx_CCR1时,OC1REF信号取反。
100:强制无效电平——强行拉低OC1REF 信号。
101:强制有效电平——强行拉高OC1REF 信号。
110:PWM模式1——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1有效,反之无效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1无效(OC1REF=0),反之有效(OC1REF=1)。
110:PWM模式2——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1无效,反之有效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1有效,反之无效。
我用红色标出了提到有效、无效的地方。不难发现,有效与无效分别对应OC1REF=1和OC1REF=0。这正是我们先前约定的结果。
到此,不同模式下输出比较的结果对OC1REF信号的影响已经很清楚了,但是最终的输出信号是OC1,并不是OC1REF。而且前面有一句话(输出信号的极性体现在信号链的末端)还未做解释。
到底OC1REF与OC1之间有何秘密呢?我们来看下面这个图:
STM32定时器输出比较模式中的疑惑
显然,我们只关心红色圈内的信号与方框内的寄存器位以及信号在它们之间是如何传播的。
oc1ref从输出模式控制器(Output mode controller)开始,分为两路,上面一路至主模式控制器(To the master mode controller),这里我们不关心它的去向,我们关心的是下面一路,下面一路在进入双路开关之前又被分成了两路——一路是原信号,一路是原信号的非。显然TIMx_CCER中的CC1P位用来控制这个开关,CC1E位控制着整条信号链的通断。
当CC1P=0时(CC1E=1):



当CC1P=1时(CC1E=1):
很显然,OC1与OC1REF的关系只受CC1P的影响(CC1E=1)
STM32定时器输出比较模式中的疑惑

然而参考手册上对CC1P位是这么描述的:
STM32定时器输出比较模式中的疑惑
CC1P=0时:OC1高电平有效
CC1P=1时:OC1低电平有效
根据本文开篇的名词解释,可以这么理解:
CC1P=0时:OC1有效电平是高电平
CC1P=1时:OC1有效电平是低电平
这时就迷惑了,这个高电平有效和低电平有效是啥意思呢?
我们从头分析(整个过程CC1E=1,OC1的输出是允许的):
①假定OC1REF有效(OC1REF=1),那么从OC1REF到OC1的整条信号链上的信号都是有效信号,我们称OC1输出了有效信号。
那这个有效信号是高电平还是低电平呢?
这就是由CC1P决定的:
STM32定时器输出比较模式中的疑惑

②假定OC1REF无效(OC1REF=0),那么从OC1REF到OC1的整条信号链上的信号都是无效信号,我们称OC1输出了无效信号。
无效信号的高电平和低电平也是由CC1P决定:
STM32定时器输出比较模式中的疑惑
用一张表来总结上述过程:
OC1REF
CC1P
功能
OC1
描述
0
0
OC1高电平有效
0(低电平)
无效
1
OC1低电平有效
1(高电平)
无效
1
0
OC1高电平有效
1(高电平)
有效
1
OC1低电平有效
0(低电平)
有效
显然,OC1REF决定了OC1输出电平是否有效,而CC1P决定了有效电平的极性。
我们抽出上表的后四列:
CC1P
功能
OC1
描述
0
OC1高电平有效
0(低电平)
无效
1
OC1低电平有效
1(高电平)
无效
0
OC1高电平有效
1(高电平)
有效
1
OC1低电平有效
0(低电平)
有效
我们将表按1、2列合并
CC1P
功能
OC1
描述
0

OC1高电平有效
0(低电平)
无效
OC1高电平有效
1(高电平)
有效
1

OC1低电平有效
0(低电平)
有效
OC1低电平有效
1(高电平)
无效
现在很清楚了,从上表中可以清楚地看到CC1P对OC1有效极性的控制。即,OC1的极性只有与CC1P指定的有效极性一致,OC1才能是有效的(绿色部分)。这样就解释了“输出信号的极性体现在信号链的末端”这句话。
然而这条链还未结束,还有个CC1E呢。当然,它就是一个OC1输出使能位而已。
但细心的你可能会发现,参考手册上对CC1E位有这样的描述:
STM32定时器输出比较模式中的疑惑
OCx = OCxREF + Polarity
这个式子告诉我们OCx与OCxREF和Polarity(极性,即CCxP位)的关系。
我们上面提到了它们的关系,是分了两种情况(CC1P=0和CC1P=1)表示的,这个式子帮我们将上面关系归纳成了一个。这个式子怎么得来的?
回忆一下数字电路里面的半加器(就是不进位的加法),真值表如下:
OCxREF
Polarity
OCx
0(无效)
0(高有效)
0(无效)
0(无效)
1(低有效)
1(无效)
1(有效)
0(高有效)
1(有效)
1(有效)
1(低有效)
0(有效)
我们写逻辑函数(按黄色部分写):
STM32定时器输出比较模式中的疑惑

STM32定时器输出比较模式中的疑惑

注意:前面的“+”号表示半加运算(不进位加法),其实是逻辑上的“异或”。
OC1连接到TIMx_CH1上,而TIMx_CH1是复用的。可在参考手册上定时器功能复用部分找到。
下面给出一些定时器功能复用的表格:

TM32的每个定时器都可以由另一个定时器触发启动定时器一般是通过软件设置而启动,STM32的每个定时器也可以通过外部信号触发而启动,还可以通过另外一个定时器的某一个条件被触发而启动.这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件.这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式 查看全部
STM32的每个定时器都可以由另一个定时器触发启动

定时器一般是通过软件设置而启动,STM32的每个定时器也可以通过外部信号触发而启动,还可以通过另外一个定时器的某一个条件被触发而启动。这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件。

这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式。

STM32定时器输出比较模式中的疑

OCx与OCxREF和CCxP之间的关系
初学STM32,我这个地方卡了很久,现在终于有些明白了,现在把我的理解写下与大家共享,如果有不对的地方,还请指出。
OCxREF就是一个参考信号,并且约定:
OCxREF=1,称OCxREF有效。反之,OCxREF=0,称OCxREF无效;
‘1’电平(高电平)称为OCxREF的有效电平,‘0’ 电平(低电平)称为OCxREF的无效电平。
——依据参考手册:The output stage generates an intermediate waveform which is then used for reference:OCxRef (active high). The polarity acts at the end of the chain.
(翻译)输出阶段产生一个中间波形OCxRef(高有效)作为参考。输出信号的极性体现在信号链的末端。
现在解释几个名词之间的关系:
STM32定时器输出比较模式中的疑惑
然后来理解输出比较的几个模式(PWM模式是输出比较模式的特例)
查看TIMx_CCMR1寄存器的OC1M域,有如下定义(摘自最新版的参考手册)
STM32定时器输出比较模式中的疑惑
翻译如下:
000:冻结——输出比较寄存器TIMx_CCR1中的内容与计数器TIMx_CNT中的内容之间的比较对输出无影响。(此模式用于时基的生成)
001:当匹配时,设置通道1为有效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉高OC1REF 信号。
010:当匹配时,设置通道1为无效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉低OC1REF 信号。
011:翻转——当TIMx_CNT= TIMx_CCR1时,OC1REF信号取反。
100:强制无效电平——强行拉低OC1REF 信号。
101:强制有效电平——强行拉高OC1REF 信号。
110:PWM模式1——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1有效,反之无效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1无效(OC1REF=0),反之有效(OC1REF=1)。
110:PWM模式2——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1无效,反之有效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1有效,反之无效。
我用红色标出了提到有效、无效的地方。不难发现,有效与无效分别对应OC1REF=1和OC1REF=0。这正是我们先前约定的结果。
到此,不同模式下输出比较的结果对OC1REF信号的影响已经很清楚了,但是最终的输出信号是OC1,并不是OC1REF。而且前面有一句话(输出信号的极性体现在信号链的末端)还未做解释。
到底OC1REF与OC1之间有何秘密呢?我们来看下面这个图:
STM32定时器输出比较模式中的疑惑
显然,我们只关心红色圈内的信号与方框内的寄存器位以及信号在它们之间是如何传播的。
oc1ref从输出模式控制器(Output mode controller)开始,分为两路,上面一路至主模式控制器(To the master mode controller),这里我们不关心它的去向,我们关心的是下面一路,下面一路在进入双路开关之前又被分成了两路——一路是原信号,一路是原信号的非。显然TIMx_CCER中的CC1P位用来控制这个开关,CC1E位控制着整条信号链的通断。
当CC1P=0时(CC1E=1):



当CC1P=1时(CC1E=1):
很显然,OC1与OC1REF的关系只受CC1P的影响(CC1E=1)
STM32定时器输出比较模式中的疑惑

然而参考手册上对CC1P位是这么描述的:
STM32定时器输出比较模式中的疑惑
CC1P=0时:OC1高电平有效
CC1P=1时:OC1低电平有效
根据本文开篇的名词解释,可以这么理解:
CC1P=0时:OC1有效电平是高电平
CC1P=1时:OC1有效电平是低电平
这时就迷惑了,这个高电平有效和低电平有效是啥意思呢?
我们从头分析(整个过程CC1E=1,OC1的输出是允许的):
①假定OC1REF有效(OC1REF=1),那么从OC1REF到OC1的整条信号链上的信号都是有效信号,我们称OC1输出了有效信号。
那这个有效信号是高电平还是低电平呢?
这就是由CC1P决定的:
STM32定时器输出比较模式中的疑惑

②假定OC1REF无效(OC1REF=0),那么从OC1REF到OC1的整条信号链上的信号都是无效信号,我们称OC1输出了无效信号。
无效信号的高电平和低电平也是由CC1P决定:
STM32定时器输出比较模式中的疑惑
用一张表来总结上述过程:
OC1REF
CC1P
功能
OC1
描述
0
0
OC1高电平有效
0(低电平)
无效
1
OC1低电平有效
1(高电平)
无效
1
0
OC1高电平有效
1(高电平)
有效
1
OC1低电平有效
0(低电平)
有效
显然,OC1REF决定了OC1输出电平是否有效,而CC1P决定了有效电平的极性。
我们抽出上表的后四列:
CC1P
功能
OC1
描述
0
OC1高电平有效
0(低电平)
无效
1
OC1低电平有效
1(高电平)
无效
0
OC1高电平有效
1(高电平)
有效
1
OC1低电平有效
0(低电平)
有效
我们将表按1、2列合并
CC1P
功能
OC1
描述
0

OC1高电平有效
0(低电平)
无效
OC1高电平有效
1(高电平)
有效
1

OC1低电平有效
0(低电平)
有效
OC1低电平有效
1(高电平)
无效
现在很清楚了,从上表中可以清楚地看到CC1P对OC1有效极性的控制。即,OC1的极性只有与CC1P指定的有效极性一致,OC1才能是有效的(绿色部分)。这样就解释了“输出信号的极性体现在信号链的末端”这句话。
然而这条链还未结束,还有个CC1E呢。当然,它就是一个OC1输出使能位而已。
但细心的你可能会发现,参考手册上对CC1E位有这样的描述:
STM32定时器输出比较模式中的疑惑
OCx = OCxREF + Polarity
这个式子告诉我们OCx与OCxREF和Polarity(极性,即CCxP位)的关系。
我们上面提到了它们的关系,是分了两种情况(CC1P=0和CC1P=1)表示的,这个式子帮我们将上面关系归纳成了一个。这个式子怎么得来的?
回忆一下数字电路里面的半加器(就是不进位的加法),真值表如下:
OCxREF
Polarity
OCx
0(无效)
0(高有效)
0(无效)
0(无效)
1(低有效)
1(无效)
1(有效)
0(高有效)
1(有效)
1(有效)
1(低有效)
0(有效)
我们写逻辑函数(按黄色部分写):
STM32定时器输出比较模式中的疑惑

STM32定时器输出比较模式中的疑惑

注意:前面的“+”号表示半加运算(不进位加法),其实是逻辑上的“异或”。
OC1连接到TIMx_CH1上,而TIMx_CH1是复用的。可在参考手册上定时器功能复用部分找到。
下面给出一些定时器功能复用的表格:

TM32的每个定时器都可以由另一个定时器触发启动定时器一般是通过软件设置而启动,STM32的每个定时器也可以通过外部信号触发而启动,还可以通过另外一个定时器的某一个条件被触发而启动.这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件.这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式

stm32cube中文教程:TIM3定时1S完整代码分析与实现

软件教程admin 发表了文章 • 15 个评论 • 8848 次浏览 • 2014-10-14 00:03 • 来自相关话题

纯粹用的stm32cubemx软件自动生成,特此记录,为以后理解做准备。
要修改的我写在下面了,其他不提及的都是默认的不变即可
1,打开stm32cubemx,点PINout选项卡里面的RCC里面选项high speed clock选crystal。
同时,PINOUT选项卡里的tim3里面的clock source 选择internal clock,右边管脚画面里面选择PD12和13为输出。
额,我例子里面包含了PA0作为外部中断0口,这个你可以不用选。
好了。
2,stm32cubemx的clock选项里面设置外部8M,系统时钟168M,APB1为84M。
3,点stm32cubemx的configuration选项卡,gpio设置为推挽输出,上啦,nvic中断优先级
中断分组0,system tic timer为0,0
exti line0 interrupt 为0,1------------------这个如果上面没用到外部中断0的话就不选
Tim3 gloabal interrupt 为0,2
3,点TIM3的按钮,设置TIM3参数,Prescaler 为8399,
counter mode 为UP
counter Period为9999
master/slave mode 为 disable 不使能主从
Triggerevent selection为Update event 触发事件选事件更新
原因如下:
我这个实验是要设置PD13口的led每1S点亮和熄灭,然后循环,用定时器做,不用滴答时钟做。
即1s转换一次,即1HZ,TIM3的时钟是84Mhz。
+ Period = 10000-1 这个是定时器计数周期,即循环这么多次后产生中断
+ Prescaler = (84M/10000) - 1 这个是定时器重载数,即每次循环加载的值
要产生1s,就是10000*0.0001s,即10000次10kHZ,
所以 + Period = 10000 - 1 减1是因为从0开始计数嘛
+ Prescaler = ((SystemCoreClock/2)/10000) - 1
4,自动生成代码。
keil打开生成的代码,main中添加
HAL_TIM_Base_Start_IT (&htim3 );
文件尾部添加
(sorry,原来写错了,写成了外部中断里面的那个函数,汗,改回来了)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD ,GPIO_PIN_13);
}

完整main代码如下:


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
TIM_HandleTypeDef htim3;

/[i] USER CODE BEGIN 0 [/i]/

/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] System interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_TIM3_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_12);
HAL_Delay (1000);
}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] TIM3 init function [/i]/
void MX_TIM3_Init(void)
{

TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOH_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
__GPIOD_CLK_ENABLE();

/[i]Configure GPIO pin : PA0 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/[i]Configure GPIO pins : PD12 PD13 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

/[i] EXTI interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD ,GPIO_PIN_13);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_13);
}

/[i] USER CODE END 4 [/i]/ 查看全部
纯粹用的stm32cubemx软件自动生成,特此记录,为以后理解做准备。
要修改的我写在下面了,其他不提及的都是默认的不变即可
1,打开stm32cubemx,点PINout选项卡里面的RCC里面选项high speed clock选crystal。
同时,PINOUT选项卡里的tim3里面的clock source 选择internal clock,右边管脚画面里面选择PD12和13为输出。
额,我例子里面包含了PA0作为外部中断0口,这个你可以不用选。
好了。
2,stm32cubemx的clock选项里面设置外部8M,系统时钟168M,APB1为84M。
3,点stm32cubemx的configuration选项卡,gpio设置为推挽输出,上啦,nvic中断优先级
中断分组0,system tic timer为0,0
exti line0 interrupt 为0,1------------------这个如果上面没用到外部中断0的话就不选
Tim3 gloabal interrupt 为0,2
3,点TIM3的按钮,设置TIM3参数,Prescaler 为8399,
counter mode 为UP
counter Period为9999
master/slave mode 为 disable 不使能主从
Triggerevent selection为Update event 触发事件选事件更新
原因如下:
我这个实验是要设置PD13口的led每1S点亮和熄灭,然后循环,用定时器做,不用滴答时钟做。
即1s转换一次,即1HZ,TIM3的时钟是84Mhz。
+ Period = 10000-1 这个是定时器计数周期,即循环这么多次后产生中断
+ Prescaler = (84M/10000) - 1 这个是定时器重载数,即每次循环加载的值
要产生1s,就是10000*0.0001s,即10000次10kHZ,
所以 + Period = 10000 - 1 减1是因为从0开始计数嘛
+ Prescaler = ((SystemCoreClock/2)/10000) - 1
4,自动生成代码。
keil打开生成的代码,main中添加
HAL_TIM_Base_Start_IT (&htim3 );
文件尾部添加
(sorry,原来写错了,写成了外部中断里面的那个函数,汗,改回来了)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD ,GPIO_PIN_13);
}

完整main代码如下:


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
TIM_HandleTypeDef htim3;

/[i] USER CODE BEGIN 0 [/i]/

/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] System interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_TIM3_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_12);
HAL_Delay (1000);
}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] TIM3 init function [/i]/
void MX_TIM3_Init(void)
{

TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOH_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
__GPIOD_CLK_ENABLE();

/[i]Configure GPIO pin : PA0 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/[i]Configure GPIO pins : PD12 PD13 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

/[i] EXTI interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD ,GPIO_PIN_13);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_13);
}

/[i] USER CODE END 4 [/i]/

巧计APB1(低速外设)APB2(高速外设)上的所对应的外设

经验分享admin 发表了文章 • 0 个评论 • 1528 次浏览 • 2014-10-14 00:01 • 来自相关话题

巧计APB1(低速外设)APB2(高速外设)上的所对应的外设
连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。

连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。 查看全部
巧计APB1(低速外设)APB2(高速外设)上的所对应的外设
连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。

连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。

stm32中的stm32中的中断与事件触发的区别与理解,external event mode 与external interrupt mode的区别

经验分享admin 发表了文章 • 2 个评论 • 2263 次浏览 • 2014-10-13 23:58 • 来自相关话题

这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚进入,经过编号2的边沿检测电路,通过编号3的或门进入中断挂起请求寄存器,最后经过编号4的与门输出到NVIC中断检测电路,这个边沿检测电路受上升沿或下降沿选择寄存器控制,用户可以使用这两个寄存器控制需要哪一个边沿产生中断,因为选择上升沿或下降沿是分别受2个平行的寄存器控制,所以用户可以同时选择上升沿或下降沿,而如果只有一个寄存器控制,那么只能选择一个边沿了.
按下来是编号3的或门,这个或门的另一个输入是软件中断/事件寄存器,从这里可以看出,软件可以优先于外部信号请求一个中断或事件,即当软件中断/事件寄存器的对应位为"1"时,不管外部信号如何,编号3的或门都会输出有效信号.
一个中断或事件请求信号经过编号3的或门后,进入挂起请求寄存器,到此之前,中断和事件的信号传输通路都是一致的,也就是说,挂起请求寄存器中记录了外部信号的电平变化.
外部请求信号最后经过编号4的与门,向NVIC中断控制器发出一个中断请求,如果中断屏蔽寄存器的对应位为"0",则该请求信号不能传输到与门的另一端,实现了中断的屏蔽.
明白了外部中断的请求机制,就很容易理解事件的请求机制了.图中红色虚线箭头,标出了外部事件信号的传输路径,外部请求信号经过编号3的或门后,进入编号5的与门,这个与门的作用与编号4的与门类似,用于引入事件屏蔽寄存器的控制;最后脉冲发生器的一个跳变的信号转变为一个单脉冲,输出到芯片中的其它功能模块.从这张图上我们也可以知道,从外部激励信号来看,中断和事件的产生源都可以是一样的.之所以分成2个部分,由于中断是需要CPU参与的,需要软件的中断服务函数才能完成中断后产生的结果;但是事件,是靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,比如引起DMA操作,AD转换等;
简单举例:外部I/O触发AD转换,来测量外部物品的重量;如果使用传统的中断通道,需要I/O触发产生外部中断,外部中断服务程序启动AD转换,AD转换完成中断服务程序提交最后结果;要是使用事件通道,I/O触发产生事件,然后联动触发AD转换,AD转换完成中断服务程序提交最后结果;相比之下,后者不要软件参与AD触发,并且响应速度也更块;要是使用事件触发DMA操作,就完全不用软件参与就可以完成某些联动任务了。
总结:
可以这样简单的认为,事件机制提供了一个完全有硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法; 查看全部

这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚进入,经过编号2的边沿检测电路,通过编号3的或门进入中断挂起请求寄存器,最后经过编号4的与门输出到NVIC中断检测电路,这个边沿检测电路受上升沿或下降沿选择寄存器控制,用户可以使用这两个寄存器控制需要哪一个边沿产生中断,因为选择上升沿或下降沿是分别受2个平行的寄存器控制,所以用户可以同时选择上升沿或下降沿,而如果只有一个寄存器控制,那么只能选择一个边沿了.
按下来是编号3的或门,这个或门的另一个输入是软件中断/事件寄存器,从这里可以看出,软件可以优先于外部信号请求一个中断或事件,即当软件中断/事件寄存器的对应位为"1"时,不管外部信号如何,编号3的或门都会输出有效信号.
一个中断或事件请求信号经过编号3的或门后,进入挂起请求寄存器,到此之前,中断和事件的信号传输通路都是一致的,也就是说,挂起请求寄存器中记录了外部信号的电平变化.
外部请求信号最后经过编号4的与门,向NVIC中断控制器发出一个中断请求,如果中断屏蔽寄存器的对应位为"0",则该请求信号不能传输到与门的另一端,实现了中断的屏蔽.
明白了外部中断的请求机制,就很容易理解事件的请求机制了.图中红色虚线箭头,标出了外部事件信号的传输路径,外部请求信号经过编号3的或门后,进入编号5的与门,这个与门的作用与编号4的与门类似,用于引入事件屏蔽寄存器的控制;最后脉冲发生器的一个跳变的信号转变为一个单脉冲,输出到芯片中的其它功能模块.从这张图上我们也可以知道,从外部激励信号来看,中断和事件的产生源都可以是一样的.之所以分成2个部分,由于中断是需要CPU参与的,需要软件的中断服务函数才能完成中断后产生的结果;但是事件,是靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,比如引起DMA操作,AD转换等;
简单举例:外部I/O触发AD转换,来测量外部物品的重量;如果使用传统的中断通道,需要I/O触发产生外部中断,外部中断服务程序启动AD转换,AD转换完成中断服务程序提交最后结果;要是使用事件通道,I/O触发产生事件,然后联动触发AD转换,AD转换完成中断服务程序提交最后结果;相比之下,后者不要软件参与AD触发,并且响应速度也更块;要是使用事件触发DMA操作,就完全不用软件参与就可以完成某些联动任务了。
总结:
可以这样简单的认为,事件机制提供了一个完全有硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法;

关于RS485通讯的问题,有几个问题请大家给指教啊,越详细越好

回复

问题困惑admin 回复了问题 • 1 人关注 • 2 个回复 • 1812 次浏览 • 2014-10-13 23:52 • 来自相关话题

先转载一个,用库函数在STM32F4 定时器TIM(1)定时器控制输出

经验分享admin 发表了文章 • 1 个评论 • 1577 次浏览 • 2014-10-13 23:48 • 来自相关话题

STM32F4的高级控制定时器包含一个自动重装载计数器,计数器的输入是一个被预分频的系统时钟。

这个定时器有多种用途,包括车辆输入信号长度(输入捕获模式)或者产生波形输出(输出捕获,PWM,带死区插入的互补PWM输出等)

脉冲长度和波形周期可在通过定时器的预分频器或者RCC的预分频器在几个微秒时钟内调整。

高级控制定时器和通用定时器完全独立,不共享任何资源。

高级时钟控制定时器TIM1&TIM8的主要特性:

1、16位向上、向下、双向自动重装载计数器2、16位预分频器,分频值从1打655353、4个独立通道4、带死去输出的互补输出5、控制外部信号的同步电路6、刹车输入7、产生中断和DMA强求8、可外部触发

等等。。

TIM定时器确实很强大。至于怎么用,ST的手册不出奇的难看,完全没有条理可言。昨天看一天,都没明白是在说什么。配套的固件库也是,各种函数的介绍,函数名结构体定义完全没有逻辑可言。于是只能参照网友的介绍,从最基础的部分弄起。
【实验1、TIM1的计时功能】

【实验描述】

利用TIM1的技术功能,产生2Hz的中断每次中断LED1反转,LED1反转频率为1Hz。

根据时钟配置,系统时钟为168MHz,APB2时钟为84MHz。TIM1挂接在APB2上,所以APB2 时钟为84MHz。

因此预分频系数设置成了10000即0x2710,自动重装载计数器ARR(TIM_Period)设置成了4200即0x1068。每次计数满产生中断。

中断频率f= 84MHz /4200 / 10000 = 2Hz

【代码实现】

1、首先开启TIM1的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

2、时基单元的初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0x1068;
TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM1,TIM_FLAG_Update); //必须先清除配置时候产生的更新标志
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE); //使能中断,中断事件为定时器工薪事件
TIM_Cmd(TIM1,ENABLE); //使能定时器

3、中断处理函数

没什么可说的,反转LED灯而已。每次中断反转一次,2Hz的中断产生1Hz的闪烁。

中断名字是库里边定义的,跟TIM10全局中断公用。

void TIM1_UP_TIM10_IRQHandler(void)
{
TIM_ClearFlag(TIM1,TIM_FLAG_Update);//进入中断先清除更新标志
LEDTog(LED1);
}

之后我们就可以看到LED以大约1Hz的频率在闪烁了。

【实验2、强制输出模式实验】

百度来的强制输出模式的定义:在程序编程中,IO口一般都可以作为输入输出的。而有些数据要在让其执行时候必须执行,所以让其强制性的输出。这是IO口只能做一件事。

看完之后还是一头雾水。

简单 点说,就是不管当时IO输出的是什么,都能强制将其设为0或者为1.

【实验描述】

为了实验方便,这个实验使用TIM4的强制输出功能,点亮与GPIOD Pin13引脚相连的LED3。对于强制输出功能,高级定时器和通用定时器是完全一样的。

TIM4的CH2被复用在GPIOD 的Pin13。所以可以将这个输出强制为高,将LED点亮。

【代码实现】

1、首先将GPIO初始化为AF复用功能。

CM4的引脚复用功能和CM3的实现方法不同,要特别注意。按照CM3的写法将不会有输出
void TIM4_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_initStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);

GPIO_initStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_initStructure.GPIO_OType = GPIO_OType_PP;
GPIO_initStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_initStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_initStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD,&GPIO_initStructure);

GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_TIM4);
}

2、TIM4的初始化

这里的时钟我没有计算,因为这个实验不太关注这个。

void TIM4_Config1(void)
{
TIM4_GPIO_Config();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period =0x1068;
TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ARRPreloadConfig(TIM4,ENABLE);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;; //设置成什么模式都行。
TIM_OCInitStructure.TIM_Pulse= 1000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC2Init(TIM4,&TIM_OCInitStructure);

TIM_Cmd(TIM4,ENABLE);
}

3、在主函数中强制输出。

初始化完成之后,在任何时候都能强制引脚电平,只需要一个函数即可:

TIM_ForcedOC2Config(TIM4,TIM_ForcedAction_Active);
这个函数设置TIM的CCMR1的OCxM位为101或者100实现输出的拉高或拉低 查看全部
STM32F4的高级控制定时器包含一个自动重装载计数器,计数器的输入是一个被预分频的系统时钟。

这个定时器有多种用途,包括车辆输入信号长度(输入捕获模式)或者产生波形输出(输出捕获,PWM,带死区插入的互补PWM输出等)

脉冲长度和波形周期可在通过定时器的预分频器或者RCC的预分频器在几个微秒时钟内调整。

高级控制定时器和通用定时器完全独立,不共享任何资源。

高级时钟控制定时器TIM1&TIM8的主要特性:

1、16位向上、向下、双向自动重装载计数器2、16位预分频器,分频值从1打655353、4个独立通道4、带死去输出的互补输出5、控制外部信号的同步电路6、刹车输入7、产生中断和DMA强求8、可外部触发

等等。。

TIM定时器确实很强大。至于怎么用,ST的手册不出奇的难看,完全没有条理可言。昨天看一天,都没明白是在说什么。配套的固件库也是,各种函数的介绍,函数名结构体定义完全没有逻辑可言。于是只能参照网友的介绍,从最基础的部分弄起。
【实验1、TIM1的计时功能】

【实验描述】

利用TIM1的技术功能,产生2Hz的中断每次中断LED1反转,LED1反转频率为1Hz。

根据时钟配置,系统时钟为168MHz,APB2时钟为84MHz。TIM1挂接在APB2上,所以APB2 时钟为84MHz。

因此预分频系数设置成了10000即0x2710,自动重装载计数器ARR(TIM_Period)设置成了4200即0x1068。每次计数满产生中断。

中断频率f= 84MHz /4200 / 10000 = 2Hz

【代码实现】

1、首先开启TIM1的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

2、时基单元的初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0x1068;
TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM1,TIM_FLAG_Update); //必须先清除配置时候产生的更新标志
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE); //使能中断,中断事件为定时器工薪事件
TIM_Cmd(TIM1,ENABLE); //使能定时器

3、中断处理函数

没什么可说的,反转LED灯而已。每次中断反转一次,2Hz的中断产生1Hz的闪烁。

中断名字是库里边定义的,跟TIM10全局中断公用。

void TIM1_UP_TIM10_IRQHandler(void)
{
TIM_ClearFlag(TIM1,TIM_FLAG_Update);//进入中断先清除更新标志
LEDTog(LED1);
}

之后我们就可以看到LED以大约1Hz的频率在闪烁了。

【实验2、强制输出模式实验】

百度来的强制输出模式的定义:在程序编程中,IO口一般都可以作为输入输出的。而有些数据要在让其执行时候必须执行,所以让其强制性的输出。这是IO口只能做一件事。

看完之后还是一头雾水。

简单 点说,就是不管当时IO输出的是什么,都能强制将其设为0或者为1.

【实验描述】

为了实验方便,这个实验使用TIM4的强制输出功能,点亮与GPIOD Pin13引脚相连的LED3。对于强制输出功能,高级定时器和通用定时器是完全一样的。

TIM4的CH2被复用在GPIOD 的Pin13。所以可以将这个输出强制为高,将LED点亮。

【代码实现】

1、首先将GPIO初始化为AF复用功能。

CM4的引脚复用功能和CM3的实现方法不同,要特别注意。按照CM3的写法将不会有输出
void TIM4_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_initStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);

GPIO_initStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_initStructure.GPIO_OType = GPIO_OType_PP;
GPIO_initStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_initStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_initStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD,&GPIO_initStructure);

GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_TIM4);
}

2、TIM4的初始化

这里的时钟我没有计算,因为这个实验不太关注这个。

void TIM4_Config1(void)
{
TIM4_GPIO_Config();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period =0x1068;
TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ARRPreloadConfig(TIM4,ENABLE);

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;; //设置成什么模式都行。
TIM_OCInitStructure.TIM_Pulse= 1000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC2Init(TIM4,&TIM_OCInitStructure);

TIM_Cmd(TIM4,ENABLE);
}

3、在主函数中强制输出。

初始化完成之后,在任何时候都能强制引脚电平,只需要一个函数即可:

TIM_ForcedOC2Config(TIM4,TIM_ForcedAction_Active);
这个函数设置TIM的CCMR1的OCxM位为101或者100实现输出的拉高或拉低

stm32cube中文教程:AD用TIM8定时采集,uart3输出

软件教程admin 发表了文章 • 15 个评论 • 3973 次浏览 • 2014-10-13 23:45 • 来自相关话题

stm32cube中文教程:AD用TIM8定时采集,uart3输出
arm片子stm32f407ZGT,用ADC1,TIM8,UART3,。
ad脚PB0,uart脚PB10和11,PF6输出led灯。
晶振25M,时钟168M。
stm32cubemx软件设置:
uart9600,8,0,1,不使能uart中断,TX:PULL_up,fast。RX:NO PULL_UP,fast
DMA不使能。
ADC设置:修改了continuous conversion mode:enable;end of conversion selection :Eoc flag signle channel

External Trigger conversion Edge : Trigger detection on the rising edge
External Trigger Conversion Source : Time 8 Trigger Out event
其余的默认即可。
ADC中断不使能。
TIme8定时设置:
Prescaler(psc - 16 bits value) : 0
counter mode : UP
counter Period(autoreload register - 16 bits value) : 60
internal clock division (CDK) : NO Division
Repetition counter(RCR - 8bits value) : 0
slave mode controller : trigger mode
master/slave mode : Disable
trigger event selection : Update enent
不使能任何TIM中断,DMA不使能。
----------------------------------------------------------
以上软件配置结束,自动生成代码即可。
main文件中添加:


#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}

---------------------------------------为了能使用printf。
main()函数中添加:


/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
if(HAL_TIM_Base_Start(&htim8) != HAL_OK)
{
/[i] Counter Enable Error [/i]/
//Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",s_value);
// HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

-------------------------------------------------开启AD和TIM
底部添加:


/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
v_value += uhADCxConvertedValue;
count++;
if(count>=500) { s_value = v_value/500; v_value = 0; count=0; }
}

/[i] USER CODE END 4 [/i]/

---------------------------------------AD采集完成数据处理调用

其他文件不要变动。

下面是完整的main文件代码:


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim8;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
int32_t v_value;
int32_t s_value;
uint16_t count=0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM8_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM8_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
if(HAL_TIM_Base_Start(&htim8) != HAL_OK)
{
/[i] Counter Enable Error [/i]/
//Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",s_value);
// HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

}
/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] TIM8 init function [/i]/
void MX_TIM8_Init(void)
{

TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim8.Instance = TIM8;
htim8.Init.Prescaler = 0;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 60;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim8);

sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
HAL_TIM_SlaveConfigSynchronization(&htim8, &sSlaveConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
v_value += uhADCxConvertedValue;
count++;
if(count>=500) { s_value = v_value/500; v_value = 0; count=0; }
}

/[i] USER CODE END 4 [/i]/ 查看全部
stm32cube中文教程:AD用TIM8定时采集,uart3输出
arm片子stm32f407ZGT,用ADC1,TIM8,UART3,。
ad脚PB0,uart脚PB10和11,PF6输出led灯。
晶振25M,时钟168M。
stm32cubemx软件设置:
uart9600,8,0,1,不使能uart中断,TX:PULL_up,fast。RX:NO PULL_UP,fast
DMA不使能。
ADC设置:修改了continuous conversion mode:enable;end of conversion selection :Eoc flag signle channel

External Trigger conversion Edge : Trigger detection on the rising edge
External Trigger Conversion Source : Time 8 Trigger Out event
其余的默认即可。
ADC中断不使能。
TIme8定时设置:
Prescaler(psc - 16 bits value) : 0
counter mode : UP
counter Period(autoreload register - 16 bits value) : 60
internal clock division (CDK) : NO Division
Repetition counter(RCR - 8bits value) : 0
slave mode controller : trigger mode
master/slave mode : Disable
trigger event selection : Update enent
不使能任何TIM中断,DMA不使能。
----------------------------------------------------------
以上软件配置结束,自动生成代码即可。
main文件中添加:


#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}

---------------------------------------为了能使用printf。
main()函数中添加:


/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
if(HAL_TIM_Base_Start(&htim8) != HAL_OK)
{
/[i] Counter Enable Error [/i]/
//Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",s_value);
// HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

-------------------------------------------------开启AD和TIM
底部添加:


/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
v_value += uhADCxConvertedValue;
count++;
if(count>=500) { s_value = v_value/500; v_value = 0; count=0; }
}

/[i] USER CODE END 4 [/i]/

---------------------------------------AD采集完成数据处理调用

其他文件不要变动。

下面是完整的main文件代码:


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim8;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
int32_t v_value;
int32_t s_value;
uint16_t count=0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM8_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM8_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
if(HAL_TIM_Base_Start(&htim8) != HAL_OK)
{
/[i] Counter Enable Error [/i]/
//Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",s_value);
// HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

}
/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] TIM8 init function [/i]/
void MX_TIM8_Init(void)
{

TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim8.Instance = TIM8;
htim8.Init.Prescaler = 0;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 60;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim8);

sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
HAL_TIM_SlaveConfigSynchronization(&htim8, &sSlaveConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
v_value += uhADCxConvertedValue;
count++;
if(count>=500) { s_value = v_value/500; v_value = 0; count=0; }
}

/[i] USER CODE END 4 [/i]/

(转载)温控器PID算法的实现(C语言),未实验

新手交流admin 发表了文章 • 0 个评论 • 1370 次浏览 • 2014-10-13 23:42 • 来自相关话题

硬件原理:加热电阻为400,电源为市电,固态继电器控制通断,并提取市电的过零信号,单片机采用mega48,继电器通断最小时间为10ms,通断PWM的周期为100个过零信号.

本程序采用绝对式PID算法,当温度相差很多时,采用P算法(比例算法),当到达设定温度时,采用PID算法,实际实用稳定性还可以,上下波动在0.5度以内.

#include <avr/io.h>
#include "PID.h"
//static PID sPID;
//static PID *sptr=&sPID;
TADD Tadd1;
TADD Tadd2;
void IncPIDInit(PID *sptr)
{
sptr->SumError=0;
sptr->LastError=0;
sptr->PrevError=0;

//sptr->Proportion = 900;
//sptr->Integral=20;
//sptr->Derivative = 2;

//sptr->SetPoint = 0;
}



typedef struct
{
int SetPoint; //设定目标值
int32_t SumError; //误差累计

//int Proportion;
//int Integral; //积分常数
//int Derivative; //微分常数

int LastError; //Error[-1]
int PrevError; //Error[-2]
}PID;
#define PID_Proportion 900 //比例常数
#define PID_Integral 20 //积分常数
#define PID_Derivative 2 //微分常数
#define PWM_T 100
#define MAX_T 80 //加热的最大温度
typedef struct
{
PID spid; //PID控制器
unsigned char pwm_H;//输出
unsigned char EnAdd;//加热使能
int real_T; //实际温度值
unsigned char Taddset[3]; //加热的设定温度
unsigned char set_NO; //加热的档数
unsigned char errorflg;
unsigned char addokflg;
}TADD;

void LocPIDCalc(TADD *sptr)
{
int iError,dError;
int32_t result;
iError = (sptr->spid.SetPoint*4) - (sptr->real_T/4);
//sptr->spid.LastError = iError;
if(iError>-2&&iError<4)
{
sptr->addokflg=1;
sptr->spid.SumError +=iError;
dError = iError-sptr->spid.LastError;
sptr->spid.LastError = iError;
result=(PID_Proportion * iError +
PID_Integral * sptr->spid.SumError +
PID_Derivative * dError)/20;
}
else
{
sptr->spid.SumError =0;
sptr->spid.LastError=0;
if(iError>0)
sptr->addokflg=0;
result=(PID_Proportion * iError)/20;
}
if(result>PWM_T)
result=PWM_T;
else if(result<0)
result=0;
if((sptr->real_T>>4)>MAX_T||sptr->errorflg==0)
result=0;
sptr->pwm_H=(unsigned char) result;
//return (unsigned char) result;
} 查看全部
硬件原理:加热电阻为400,电源为市电,固态继电器控制通断,并提取市电的过零信号,单片机采用mega48,继电器通断最小时间为10ms,通断PWM的周期为100个过零信号.

本程序采用绝对式PID算法,当温度相差很多时,采用P算法(比例算法),当到达设定温度时,采用PID算法,实际实用稳定性还可以,上下波动在0.5度以内.

#include <avr/io.h>
#include "PID.h"
//static PID sPID;
//static PID *sptr=&sPID;
TADD Tadd1;
TADD Tadd2;
void IncPIDInit(PID *sptr)
{
sptr->SumError=0;
sptr->LastError=0;
sptr->PrevError=0;

//sptr->Proportion = 900;
//sptr->Integral=20;
//sptr->Derivative = 2;

//sptr->SetPoint = 0;
}



typedef struct
{
int SetPoint; //设定目标值
int32_t SumError; //误差累计

//int Proportion;
//int Integral; //积分常数
//int Derivative; //微分常数

int LastError; //Error[-1]
int PrevError; //Error[-2]
}PID;
#define PID_Proportion 900 //比例常数
#define PID_Integral 20 //积分常数
#define PID_Derivative 2 //微分常数
#define PWM_T 100
#define MAX_T 80 //加热的最大温度
typedef struct
{
PID spid; //PID控制器
unsigned char pwm_H;//输出
unsigned char EnAdd;//加热使能
int real_T; //实际温度值
unsigned char Taddset[3]; //加热的设定温度
unsigned char set_NO; //加热的档数
unsigned char errorflg;
unsigned char addokflg;
}TADD;

void LocPIDCalc(TADD *sptr)
{
int iError,dError;
int32_t result;
iError = (sptr->spid.SetPoint*4) - (sptr->real_T/4);
//sptr->spid.LastError = iError;
if(iError>-2&&iError<4)
{
sptr->addokflg=1;
sptr->spid.SumError +=iError;
dError = iError-sptr->spid.LastError;
sptr->spid.LastError = iError;
result=(PID_Proportion * iError +
PID_Integral * sptr->spid.SumError +
PID_Derivative * dError)/20;
}
else
{
sptr->spid.SumError =0;
sptr->spid.LastError=0;
if(iError>0)
sptr->addokflg=0;
result=(PID_Proportion * iError)/20;
}
if(result>PWM_T)
result=PWM_T;
else if(result<0)
result=0;
if((sptr->real_T>>4)>MAX_T||sptr->errorflg==0)
result=0;
sptr->pwm_H=(unsigned char) result;
//return (unsigned char) result;
}

什么事fifo模式,stm32f407的DMA模式怎么理解?

经验分享admin 发表了文章 • 1 个评论 • 1266 次浏览 • 2014-10-13 23:40 • 来自相关话题

fifo??什么是fifo呢??

正如它的英文名字first in first out,先进先出.....

优缺点:

他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

为什么使用fifo呢??这个问题貌似困扰了我好久了......(这两个例子网上copy,感觉不错)

FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端时AD数据采集,另一端时计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。

另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

FIFO的一些重要参数:

fifo是fpga内嵌有的,有几个参数需要设置:megawizard中可以设置.....

FIFO的宽度:及时你输出的字节的宽度....这个megawizard可以设置的....

FIFO的深度:深度??貌似很难理解....可以理解为你定义的fifo存储器中有多少字节(这个字节就是你上面定义的);

那么fifo的总字节=FIFO的宽度*FIFO的深度;

满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:指向下一个读出地址。读完后自动加1。
写指针:指向下一个要写入的地址的,写完自动加1。
读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。

fifo的分类:

可以将FIFO分为同步FIFO和异步FIFO

同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。

异步FIFO是指读写时钟不一致,读写时钟是互相独立的。



FIFO设计的难点(貌似这个挺重要的)

FIFO设计的难点在于怎样判断FIFO的空/满状态??

这是每个使用fifo应当注意,这个应该很好理解了,即是满的时候不可以再写了,空的的时候不可以再读了...

还有算法,这里就省略了...




加一点时序分析吧;
其中wrreq 和 rdreq 都是高有效即是wrreq =1是则写入,rdreq=1时读出,
神呀,如果两个都为高呢??这个我是理解为全双工的,可以读,也可以写.....没错了,经过验证也是这样的....
还有empty是空的时候为高的................ 查看全部
fifo??什么是fifo呢??

正如它的英文名字first in first out,先进先出.....

优缺点:

他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

为什么使用fifo呢??这个问题貌似困扰了我好久了......(这两个例子网上copy,感觉不错)

FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端时AD数据采集,另一端时计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。

另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

FIFO的一些重要参数:

fifo是fpga内嵌有的,有几个参数需要设置:megawizard中可以设置.....

FIFO的宽度:及时你输出的字节的宽度....这个megawizard可以设置的....

FIFO的深度:深度??貌似很难理解....可以理解为你定义的fifo存储器中有多少字节(这个字节就是你上面定义的);

那么fifo的总字节=FIFO的宽度*FIFO的深度;

满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:指向下一个读出地址。读完后自动加1。
写指针:指向下一个要写入的地址的,写完自动加1。
读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。

fifo的分类:

可以将FIFO分为同步FIFO和异步FIFO

同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。

异步FIFO是指读写时钟不一致,读写时钟是互相独立的。



FIFO设计的难点(貌似这个挺重要的)

FIFO设计的难点在于怎样判断FIFO的空/满状态??

这是每个使用fifo应当注意,这个应该很好理解了,即是满的时候不可以再写了,空的的时候不可以再读了...

还有算法,这里就省略了...




加一点时序分析吧;
其中wrreq 和 rdreq 都是高有效即是wrreq =1是则写入,rdreq=1时读出,
神呀,如果两个都为高呢??这个我是理解为全双工的,可以读,也可以写.....没错了,经过验证也是这样的....
还有empty是空的时候为高的................

stm32cube中文教程:stm32cube中使用DMA配置方法和例子

软件教程admin 发表了文章 • 1 个评论 • 3377 次浏览 • 2014-10-13 23:38 • 来自相关话题

本实验只是独立测试DMA的运作,没有实现其他功能,DMA可以添加到UART,I2C等接口的驱动中使用。
程序代码由软件stm32cubemx点击设置自动完成,除了main中添加了数据表,调用了反馈函数,
其他都未曾改动,初步测试DMA可使用。
下面是软件操作:
第一步,配置了高速时钟管脚,点击了PIN的相应脚。
第二步,配置时钟,配置P,M,Q,系统为168M频率。
第三步,点击DMA的配置按钮,选择了DMA2,0通道,M2M模式,高速,data宽度为word
其他未变,选择默认。
第四步,配置NVIC,选择优先级分组3,设置DMA的中断优先级为1,0
滴答时钟的优先级不变。
然后导出了代码,用keil打开。
main文件中,在main()中的 MX_DMA_Init();下面直接添加了代码:
hdma_memtomem_dma2_stream0.XferCpltCallback = TransferCompletecc;
hdma_memtomem_dma2_stream0.XferErrorCallback = TransferErrorcc;
意思是,正常传输的话调用名字为TransferCompletecc的函数,错误传输的话调用TransferErrorcc的函数。
然后继续添加:
if(HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
/ Transfer Error /
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1);
}
意思是:开启DMA的全部中断,顺便传输数据,aSRC_Const_Buffer和aDST_Buffer是前面定义的数据表。
注意:外围添加TransferCompletecc的函数和TransferErrorcc的函数
,然后直接编译,烧录,测试通过,观察aSRC_Const_Buffer和aDST_Buffer的数据是否一样,
相同的话说明DMA传输正确。
ok,下面上完整的main文件代码。其他文件自动生成后不需改动。
#include "stm32f4xx_hal.h"

/ Private variables ---------------------------------------------------------/
DMA_HandleTypeDef hdma_memtomem_dma2_stream0;

/ USER CODE BEGIN 0 /
#define BUFFER_SIZE 32

static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

static uint32_t aDST_Buffer[BUFFER_SIZE];

static void TransferCompletecc(DMA_HandleTypeDef *DmaHandle);
static void TransferErrorcc(DMA_HandleTypeDef *DmaHandle);
/ USER CODE END 0 /

/ Private function prototypes -----------------------------------------------/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);

int main(void)
{

/ USER CODE BEGIN 1 /

/ USER CODE END 1 /

/ MCU Configuration----------------------------------------------------------/

/ Reset of all peripherals, Initializes the Flash interface and the Systick. /
HAL_Init();

/ Configure the system clock /
SystemClock_Config();

/ System interrupt init/
/ Sets the priority grouping field /
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_1);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/ Initialize all configured peripherals /
MX_GPIO_Init();
MX_DMA_Init();

/ USER CODE BEGIN 2 /
hdma_memtomem_dma2_stream0.XferCpltCallback = TransferCompletecc;
hdma_memtomem_dma2_stream0.XferErrorCallback = TransferErrorcc;
//if(HAL_DMA_GetState != HAL_OK )
//{ HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET ); while(1); }
if(HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
/ Transfer Error /
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1);
}

/ USER CODE END 2 /

/ USER CODE BEGIN 3 /
/ Infinite loop /
while (1)
{
// HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
// HAL_Delay (1000);
}
/ USER CODE END 3 /

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/**
* Enable DMA controller clock
* Configure DMA for memory to memory transfers
* hdma_memtomem_dma2_stream0
*/
void MX_DMA_Init(void)
{
/ DMA controller clock enable /
__DMA2_CLK_ENABLE();

/ Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 /
hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH;
hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;



HAL_DMA_Init(&hdma_memtomem_dma2_stream0);

/ DMA interrupt init /
/ Sets the priority grouping field /
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_1);
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/ GPIO Ports Clock Enable /
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();

/Configure GPIO pin : PF6 /
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/ USER CODE BEGIN 4 /
static void TransferCompletecc(DMA_HandleTypeDef *DmaHandle)
{
/ Turn LED1 on: Transfer correct /
while(1){
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_Delay (3000);
}
}

/**
* @brief DMA conversion error callback
* @note This function is executed when the transfer error interrupt
* is generated during DMA transfer
* @retval None
*/
static void TransferErrorcc(DMA_HandleTypeDef *DmaHandle)
{
/ Turn LED2 on: Transfer Error /
while(1){
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_Delay (100);
}
}
/ USER CODE END 4 / 查看全部
本实验只是独立测试DMA的运作,没有实现其他功能,DMA可以添加到UART,I2C等接口的驱动中使用。
程序代码由软件stm32cubemx点击设置自动完成,除了main中添加了数据表,调用了反馈函数,
其他都未曾改动,初步测试DMA可使用。
下面是软件操作:
第一步,配置了高速时钟管脚,点击了PIN的相应脚。
第二步,配置时钟,配置P,M,Q,系统为168M频率。
第三步,点击DMA的配置按钮,选择了DMA2,0通道,M2M模式,高速,data宽度为word
其他未变,选择默认。
第四步,配置NVIC,选择优先级分组3,设置DMA的中断优先级为1,0
滴答时钟的优先级不变。
然后导出了代码,用keil打开。
main文件中,在main()中的 MX_DMA_Init();下面直接添加了代码:
hdma_memtomem_dma2_stream0.XferCpltCallback = TransferCompletecc;
hdma_memtomem_dma2_stream0.XferErrorCallback = TransferErrorcc;
意思是,正常传输的话调用名字为TransferCompletecc的函数,错误传输的话调用TransferErrorcc的函数。
然后继续添加:
if(HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
/ Transfer Error /
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1);
}
意思是:开启DMA的全部中断,顺便传输数据,aSRC_Const_Buffer和aDST_Buffer是前面定义的数据表。
注意:外围添加TransferCompletecc的函数和TransferErrorcc的函数
,然后直接编译,烧录,测试通过,观察aSRC_Const_Buffer和aDST_Buffer的数据是否一样,
相同的话说明DMA传输正确。
ok,下面上完整的main文件代码。其他文件自动生成后不需改动。
#include "stm32f4xx_hal.h"

/ Private variables ---------------------------------------------------------/
DMA_HandleTypeDef hdma_memtomem_dma2_stream0;

/ USER CODE BEGIN 0 /
#define BUFFER_SIZE 32

static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

static uint32_t aDST_Buffer[BUFFER_SIZE];

static void TransferCompletecc(DMA_HandleTypeDef *DmaHandle);
static void TransferErrorcc(DMA_HandleTypeDef *DmaHandle);
/ USER CODE END 0 /

/ Private function prototypes -----------------------------------------------/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);

int main(void)
{

/ USER CODE BEGIN 1 /

/ USER CODE END 1 /

/ MCU Configuration----------------------------------------------------------/

/ Reset of all peripherals, Initializes the Flash interface and the Systick. /
HAL_Init();

/ Configure the system clock /
SystemClock_Config();

/ System interrupt init/
/ Sets the priority grouping field /
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_1);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/ Initialize all configured peripherals /
MX_GPIO_Init();
MX_DMA_Init();

/ USER CODE BEGIN 2 /
hdma_memtomem_dma2_stream0.XferCpltCallback = TransferCompletecc;
hdma_memtomem_dma2_stream0.XferErrorCallback = TransferErrorcc;
//if(HAL_DMA_GetState != HAL_OK )
//{ HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET ); while(1); }
if(HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
/ Transfer Error /
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1);
}

/ USER CODE END 2 /

/ USER CODE BEGIN 3 /
/ Infinite loop /
while (1)
{
// HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
// HAL_Delay (1000);
}
/ USER CODE END 3 /

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/**
* Enable DMA controller clock
* Configure DMA for memory to memory transfers
* hdma_memtomem_dma2_stream0
*/
void MX_DMA_Init(void)
{
/ DMA controller clock enable /
__DMA2_CLK_ENABLE();

/ Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 /
hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH;
hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;



HAL_DMA_Init(&hdma_memtomem_dma2_stream0);

/ DMA interrupt init /
/ Sets the priority grouping field /
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_1);
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/ GPIO Ports Clock Enable /
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();

/Configure GPIO pin : PF6 /
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/ USER CODE BEGIN 4 /
static void TransferCompletecc(DMA_HandleTypeDef *DmaHandle)
{
/ Turn LED1 on: Transfer correct /
while(1){
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_Delay (3000);
}
}

/**
* @brief DMA conversion error callback
* @note This function is executed when the transfer error interrupt
* is generated during DMA transfer
* @retval None
*/
static void TransferErrorcc(DMA_HandleTypeDef *DmaHandle)
{
/ Turn LED2 on: Transfer Error /
while(1){
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_Delay (100);
}
}
/ USER CODE END 4 /

stm32cube中文教程:AD中断采集

软件教程admin 发表了文章 • 4 个评论 • 8920 次浏览 • 2014-10-13 23:32 • 来自相关话题

stm32cubemx学习笔记之AD中断采集
PB0模拟输入,uart3发送到串口观察,采用ADC1,2分频,12位,连续采集,软件触发,通道8
程序除了main中的修改了一点,其余全部由stm32cubemx自动生成。


/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

main中直接调用库函数来处理中断数据


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
}

以下是main中的全部代码:


#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/
// int32_t value;
/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",uhADCxConvertedValue);
HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
}

/[i] USER CODE END 4 [/i]/ 查看全部
stm32cubemx学习笔记之AD中断采集
PB0模拟输入,uart3发送到串口观察,采用ADC1,2分频,12位,连续采集,软件触发,通道8
程序除了main中的修改了一点,其余全部由stm32cubemx自动生成。


/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

main中直接调用库函数来处理中断数据


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
}

以下是main中的全部代码:


#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/
// int32_t value;
/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process and enable interrupt [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size]
if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
// Error_Handler();
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
HAL_Delay (5000);
}
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{

HAL_Delay (1000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);
printf ("%d",uhADCxConvertedValue);
HAL_ADC_Start_IT(&hadc1);
}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/[i] Get the converted value of regular channel [/i]/
uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle);
}

/[i] USER CODE END 4 [/i]/

教程:STM32之ADC配置,ADC_Mode模式理解(转载)

经验分享admin 发表了文章 • 0 个评论 • 3687 次浏览 • 2014-10-13 23:27 • 来自相关话题

对于STM32,在使用ADC的时候需要配置几个参数。

(1) 第一个参数是ADC_Mode,这里设置为独立模式:

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。

(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。

(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。

(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:

1、第一种是最简单的软件触发,参数为ADC_ExternalTrigConv_None。设置好后还要记得调用库函数:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

这样触发才会启动。

2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、

ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以

ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:


void TIM2_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;





TIM_TimeBaseStructure.TIM_Prescaler = 4;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseStructure.TIM_Period = 0XFF;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);





TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = 0X7F;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;



TIM_OC2Init(TIM2, &TIM_OCInitStructure);





TIM_Cmd(TIM2, ENABLE);





TIM_CtrlPWMOutputs(TIM2, ENABLE);

}


这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。

3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。

(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。

(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:


ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);

ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);


多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。



补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。 查看全部
对于STM32,在使用ADC的时候需要配置几个参数。

(1) 第一个参数是ADC_Mode,这里设置为独立模式:

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

在这个模式下,双ADC不能同步,每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候,就应该设成独立模式了。

(2) 第二个参数是ADC_ScanConvMode,这里设置为DISABLE。

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

如果只是用了一个通道的话,DISABLE就可以了,如果使用了多个通道的话,则必须将其设置为ENABLE。

(3) 第三个参数是ADC_ContinuousConvMode,这里设置为ENABLE,即连续转换。如果设置为DISABLE,则是单次转换。两者的区别在于连续转换直到所有的数据转换完成后才停止转换,而单次转换则只转换一次数据就停止,要再次触发转换才可以。所以如果需要一次性采集1024个数据或者更多,则采用连续转换。

(4) 第四个参数是ADC_ExternalTrigConv,即选择外部触发模式。这里只讲三种:

1、第一种是最简单的软件触发,参数为ADC_ExternalTrigConv_None。设置好后还要记得调用库函数:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

这样触发才会启动。

2、第二种是定时器通道输出触发。共有这几种:ADC_ExternalTrigConv_T1_CC1、ADC_ExternalTrigConv_T1_CC2、ADC_ExternalTrigConv_T2_CC2、

ADC_ExternalTrigConv_T3_T以及ADC_ExternalTrigConv_T4_CC4。定时器输出触发比较麻烦,还需要设置相应的定时器。以

ADC_ExternalTrigConv_T2_CC2触发为例设置相应的定时器:


void TIM2_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;





TIM_TimeBaseStructure.TIM_Prescaler = 4;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseStructure.TIM_Period = 0XFF;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);





TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = 0X7F;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;



TIM_OC2Init(TIM2, &TIM_OCInitStructure);





TIM_Cmd(TIM2, ENABLE);





TIM_CtrlPWMOutputs(TIM2, ENABLE);

}


这样设置之后就可以用定时器2的输出触发了,至于触发的周期,设置TIM2的时间即可。这里不再赘述。

3、第三种是外部引脚触发,对于规则通道,选择EXTI线11和TIM8_TRGO作为外部触发事件;而注入通道组则选择EXTI线15和TIM8_CC4作为外部触发事件。

(5) 第五个参数是ADC_DataAlign,这里设置为ADC_DataAlign_Right右对齐方式。建议采用右对齐方式,因为这样处理数据会比较方便。当然如果要从高位开始传输数据,那么采用左对齐优势就明显了。

(6) 第六个参数是ADC_NbrOfChannel,顾名思义:通道的数量。要是到多个通道采集数据的话就得设置一下这个参数。此外在规则通道组的配置函数中也许将各个通道的顺序定义一下,如:


ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_13Cycles5);

ADC_RegularChannelConfig(ADC1,ADC_Channel_14,2,ADC_SampleTime_13Cycles5);


多通道数据传输时有一点还要注意:若一个数组为ADC_ValueTab[4],且设置了两个通道:通道1和通道2,则转换结束后,ADC_ValueTab[0]和ADC_ValueTab[2]存储的是通道1的数据,而ADC_ValueTab[1]和ADC_ValueTab[3]存储的是通道2的数据。如果数组容量大则依次类推。



补充一点:在使用DMA传输数据的时候,需要设置外设地址和存储器地址,外设地址当然就是ADC的地址了,而存储器的地址如果使用8位数据的话,存储器必须定义为8位缓冲区;如果使用16位数据格式的话,存储器则为16位缓冲器,不可定义为32位或更多,否则,数据将出错。

stm32cube中文教程:利用AD测电压,uart输出电压,stm32cube的AD使用例子

软件教程admin 发表了文章 • 4 个评论 • 3264 次浏览 • 2014-10-13 23:23 • 来自相关话题

用的PB0口,ad输入,uart是9600的,用的uart3,PB10和PB11脚。
参考电压是vcc,即3300mv,12位精度,一次转换
用软件stm32cubemx直接生成的,学习记录用。


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/
int32_t value;
/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process [/size]################[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size][/size][/size]
if(HAL_ADC_Start(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
HAL_GPIO_WritePin (GPIOF ,GPIO_PIN_6,GPIO_PIN_SET );
}
HAL_ADC_PollForConversion(&hadc1, 10);

/[i] Check if the continous conversion of regular channel is finished [/i]/
if(HAL_ADC_GetState(&hadc1) == HAL_ADC_STATE_EOC_REG)
{
/[i][size=16]-5- Get the converted value of regular channel [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/[/size][/size][/size][/size][/size][/size][/size]
uhADCxConvertedValue = HAL_ADC_GetValue(&hadc1);
}
value = uhADCxConvertedValue*3300/4096;
printf ("%d",value );
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
HAL_Delay (2000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/

/[i] USER CODE END 4 [/i]/

#ifdef USE_FULL_ASSERT

/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

}

#endif 查看全部
用的PB0口,ad输入,uart是9600的,用的uart3,PB10和PB11脚。
参考电压是vcc,即3300mv,12位精度,一次转换
用软件stm32cubemx直接生成的,学习记录用。


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
ADC_HandleTypeDef hadc1;

UART_HandleTypeDef huart3;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/[i] Variable used to get converted value [/i]/
__IO uint16_t uhADCxConvertedValue = 0;
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART3_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/
int32_t value;
/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART3_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
/[i][size=16]-3- Start the conversion process [/size]################[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size][/size][/size]
if(HAL_ADC_Start(&hadc1) != HAL_OK)
{
/[i] Start Conversation Error [/i]/
HAL_GPIO_WritePin (GPIOF ,GPIO_PIN_6,GPIO_PIN_SET );
}
HAL_ADC_PollForConversion(&hadc1, 10);

/[i] Check if the continous conversion of regular channel is finished [/i]/
if(HAL_ADC_GetState(&hadc1) == HAL_ADC_STATE_EOC_REG)
{
/[i][size=16]-5- Get the converted value of regular channel [/size]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/[/size][/size][/size][/size][/size][/size][/size]
uhADCxConvertedValue = HAL_ADC_GetValue(&hadc1);
}
value = uhADCxConvertedValue*3300/4096;
printf ("%d",value );
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
HAL_Delay (2000);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
static void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] ADC1 init function [/i]/
void MX_ADC1_Init(void)
{

ADC_ChannelConfTypeDef sConfig;
ADC_MultiModeTypeDef multimode;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

/**Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

}

/[i] USART3 init function [/i]/
void MX_USART3_UART_Init(void)
{

huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/

/[i] USER CODE END 4 [/i]/

#ifdef USE_FULL_ASSERT

/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

}

#endif

stm32中使用DMA,DMA的用法

经验分享admin 发表了文章 • 0 个评论 • 1993 次浏览 • 2014-10-13 23:18 • 来自相关话题

DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量 中断 负载。否则,CPU 需要从 来源 把每一片段的资料复制到 暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

DMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。

二.STM32使用DMA

1.DMA的设置:

要配置的有DMA传输通道选择,传输的成员和方向、普通模式还是循环模式等等。


void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //DMA访问的数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输数据大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (循环传送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

注:
1、传输通道:通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.
2、DMA传输方式:
(1) DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。
(2) DMA_Mode_Circular
循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
4、开始DMA传输(使能对应的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
LED_1_REV; //LED改变亮灭
Delay(); //浪费时间
}
当传输完成后,就会跳出上面的死循环。


/******************************************************************************
* 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()
* 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输
* 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,
* 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART
* 整个过程无需用户程序干预,用户只需启动DMA传输传输即可
* 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止
* 串口依然发送,表明DMA传输是一个独立的过程。
* 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理
* 作者:jjldc(九九)
* 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6
*******************************************************************************/
/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f10x_lib.h"
#include "stdio.h"
/[i] Private typedef -----------------------------------------------------------[/i]/
/[i] Private define ------------------------------------------------------------[/i]/
#define USART1_DR_Base 0x40013804
/[i] Private macro -------------------------------------------------------------[/i]/
/[i] Private variables ---------------------------------------------------------[/i]/
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
/[i] Private function prototypes -----------------------------------------------[/i]/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
/[i] Private functions ---------------------------------------------------------[/i]/
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;

RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();

printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

printf("Start DMA transmission!\r\n");

//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);

//等待DMA传输完成,此时我们来做另外一些事,点灯
//实际应用中,传输数据期间,可以执行另外的任务
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay(); //浪费时间
}
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);

printf("\r\nDMA transmission successful!\r\n");

/[i] Infinite loop [/i]/
while (1)
{
}
}
/*******************************************************************************
[i] Function Name : 重定义系统putchar函数int fputc(int ch, FILE [/i]f)
* Description : 串口发一个字节
[i] Input : int ch, FILE [/i]f
* Output :
* Return : int ch
* 这个是使用printf的关键
*******************************************************************************/
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;

/[i] Loop until the end of transmission [/i]/
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return ch;
}
/*******************************************************************************
* Function Name : Delay
* Description : 延时函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Delay(void)
{
u32 i;
for(i=0;i<0xF0000;i++);
return;
} 查看全部
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量 中断 负载。否则,CPU 需要从 来源 把每一片段的资料复制到 暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

DMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。

二.STM32使用DMA

1.DMA的设置:

要配置的有DMA传输通道选择,传输的成员和方向、普通模式还是循环模式等等。


void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //DMA访问的数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输数据大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (循环传送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

注:
1、传输通道:通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.
2、DMA传输方式:
(1) DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。
(2) DMA_Mode_Circular
循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
4、开始DMA传输(使能对应的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
LED_1_REV; //LED改变亮灭
Delay(); //浪费时间
}
当传输完成后,就会跳出上面的死循环。


/******************************************************************************
* 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()
* 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输
* 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,
* 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART
* 整个过程无需用户程序干预,用户只需启动DMA传输传输即可
* 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止
* 串口依然发送,表明DMA传输是一个独立的过程。
* 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理
* 作者:jjldc(九九)
* 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6
*******************************************************************************/
/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f10x_lib.h"
#include "stdio.h"
/[i] Private typedef -----------------------------------------------------------[/i]/
/[i] Private define ------------------------------------------------------------[/i]/
#define USART1_DR_Base 0x40013804
/[i] Private macro -------------------------------------------------------------[/i]/
/[i] Private variables ---------------------------------------------------------[/i]/
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
/[i] Private function prototypes -----------------------------------------------[/i]/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
/[i] Private functions ---------------------------------------------------------[/i]/
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;

RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();

printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

printf("Start DMA transmission!\r\n");

//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);

//等待DMA传输完成,此时我们来做另外一些事,点灯
//实际应用中,传输数据期间,可以执行另外的任务
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay(); //浪费时间
}
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);

printf("\r\nDMA transmission successful!\r\n");

/[i] Infinite loop [/i]/
while (1)
{
}
}
/*******************************************************************************
[i] Function Name : 重定义系统putchar函数int fputc(int ch, FILE [/i]f)
* Description : 串口发一个字节
[i] Input : int ch, FILE [/i]f
* Output :
* Return : int ch
* 这个是使用printf的关键
*******************************************************************************/
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;

/[i] Loop until the end of transmission [/i]/
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return ch;
}
/*******************************************************************************
* Function Name : Delay
* Description : 延时函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Delay(void)
{
u32 i;
for(i=0;i<0xF0000;i++);
return;
}