关于stm32cubemx生成的RTC程序的学习记录,用到RTC/usart/printf/sprintf,基于官方库例子

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

先大略的看了下官方的RTC的例子,
于是准备利用usart的printf输出,启用了stm32cube中的RTC
首先初始化了uart的printf初始化了rtc,
然后随便uart输出一个东西,
发现此时上电后,usart输出好慢,不是立马输出
于是,注释掉MX_RTC_Init();
重新烧录,输出速度正常了......
说明stm32cubemx生成的RTC初始化代码初始RTC时间长啊....不是一般的长,我还没有开始初始定义的说.
好了,2楼继续

好吧,懒得仔细搞了,就大致按照官方的例子弄下算了
过程如下:
设置此时的时间为2:20:00,2014年1月18号
定时时间为:2:20:30秒零56,2014年1月18号,
定时时间到产生中断,使LED灯亮.
ok,就按照这个来做,
下面的图示是stm32cubemx软件的相关RTC设置




















还有GPIO的设置,推挽,上拉,ok
设置完毕后自动生成代码
打开RTc.c文件,更改下面的代码为:
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;

/**Initialize RTC and set the Time and Date
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&hrtc);

sTime.Hours = 0x02;
sTime.Minutes = 0x20;
sTime.Seconds = 0;
sTime.SubSeconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT12_AM;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x18;
sDate.Year = 0x14;
HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);

/**Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0x02;
sAlarm.AlarmTime.Minutes = 0x20;
sAlarm.AlarmTime.Seconds = 0x30;
sAlarm.AlarmTime.SubSeconds = 0x56;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_None;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);

}
这个就是刚才第一步时候提到的时间,对号入座....不解释了
返回到main.c文件
在用户代码4的地方写入:
/ USER CODE BEGIN 4 /
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_RTC_AlarmAEventCallback could be implemented in the user file
*/
HAL_GPIO_WritePin (GPIOG,GPIO_PIN_6,GPIO_PIN_RESET );
}
这个是定时中断的返回调用,当中断的时候,使LED亮(我的板子是负驱动)...
ok,测试和官方实例效果一样......
30秒后led亮.....
当然这个事例子......你可以设定时间长一点,比如,好几天之后的某天..
修修补补就可以用了. 查看全部
先大略的看了下官方的RTC的例子,
于是准备利用usart的printf输出,启用了stm32cube中的RTC
首先初始化了uart的printf初始化了rtc,
然后随便uart输出一个东西,
发现此时上电后,usart输出好慢,不是立马输出
于是,注释掉MX_RTC_Init();
重新烧录,输出速度正常了......
说明stm32cubemx生成的RTC初始化代码初始RTC时间长啊....不是一般的长,我还没有开始初始定义的说.
好了,2楼继续

好吧,懒得仔细搞了,就大致按照官方的例子弄下算了
过程如下:
设置此时的时间为2:20:00,2014年1月18号
定时时间为:2:20:30秒零56,2014年1月18号,
定时时间到产生中断,使LED灯亮.
ok,就按照这个来做,
下面的图示是stm32cubemx软件的相关RTC设置

2.png


3.png


4.png


5.png

还有GPIO的设置,推挽,上拉,ok
设置完毕后自动生成代码
打开RTc.c文件,更改下面的代码为:
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;

/**Initialize RTC and set the Time and Date
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&hrtc);

sTime.Hours = 0x02;
sTime.Minutes = 0x20;
sTime.Seconds = 0;
sTime.SubSeconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT12_AM;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x18;
sDate.Year = 0x14;
HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);

/**Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0x02;
sAlarm.AlarmTime.Minutes = 0x20;
sAlarm.AlarmTime.Seconds = 0x30;
sAlarm.AlarmTime.SubSeconds = 0x56;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_None;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);

}
这个就是刚才第一步时候提到的时间,对号入座....不解释了
返回到main.c文件
在用户代码4的地方写入:
/ USER CODE BEGIN 4 /
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_RTC_AlarmAEventCallback could be implemented in the user file
*/
HAL_GPIO_WritePin (GPIOG,GPIO_PIN_6,GPIO_PIN_RESET );
}
这个是定时中断的返回调用,当中断的时候,使LED亮(我的板子是负驱动)...
ok,测试和官方实例效果一样......
30秒后led亮.....
当然这个事例子......你可以设定时间长一点,比如,好几天之后的某天..
修修补补就可以用了.

为什么fsmc控制nand,将时间都调到最大了,写入数据后读出来还是不一样啊?

回复

问题困惑admin 回复了问题 • 1 人关注 • 1 个回复 • 2625 次浏览 • 2014-10-31 17:27 • 来自相关话题

K9F1G08三星nand芯片数据的理解,数据手册怎么看?

回复

经验分享admin 回复了问题 • 1 人关注 • 1 个回复 • 1858 次浏览 • 2014-10-30 10:34 • 来自相关话题

自问自答:有人用过stm32cubemx生成的fsmc的nand程序?用stm32cube生成的代码怎么用啊?

回复

经验分享admin 回复了问题 • 1 人关注 • 2 个回复 • 5954 次浏览 • 2014-10-29 17:23 • 来自相关话题

usart的真正用法之一堆栈,push和pop处理uart得到的数据,不要再说stm32cube的新库函数不好用了

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

b[/b]

如题:
刚开始用stm32cube的最新uart库函数的时候其实我也发牢骚了半天.
甚至不知道应该怎么去处理数据..........
汗,只怪自己就没怎么认真学过,还敢自称会用uart,汗颜
以前就是直接接收到数据,然后判断处理,这个其实就是小成用法.
下面列出研究了两天的稍微大成点的用法
将uart取得的数据,经过入栈存入到一个数据表中,然后用pop出栈进行数据处理
大体做法是:
要进行传输的数据必须格式化,例如设置数据头和数据尾来判断一帧完整的数据.
数据的头和尾之间是有效数据,可以包含数据的定义和数据本身
单片机接受到数据后,先存入到
HAL_UART_Receive_IT(&huart1, que._data, QUEUE_max_size);
这句话的que._data数据表中,这个数据表可以设置的长一点,不会溢出就行
然后写一个程序处理这个里面的数据,第一步就是查找判断这个数据是不是按照上面的数据格式
的数据,如果不是则舍弃,否则,按照你的数据规则取得这个有效的数据例如queue_find_cmd(cmd_buffer,30),其中cmd_buffer里面就是得到的数据.
然后可以依照规则将每位进行分解处理,例如cmd_buffer[1]=0x00表示这次传输的是数字,=0x01则表示传输的是字符串,然后cmd_buffer[2]+(cmd_buffer[3]<<8)+(cmd_buffer[4]<<16)+(cmd_buffer[5]<<24).
这样表示后面的是连续32位数据,呵呵
2楼继续. 查看全部
b[/b]

如题:
刚开始用stm32cube的最新uart库函数的时候其实我也发牢骚了半天.
甚至不知道应该怎么去处理数据..........
汗,只怪自己就没怎么认真学过,还敢自称会用uart,汗颜
以前就是直接接收到数据,然后判断处理,这个其实就是小成用法.
下面列出研究了两天的稍微大成点的用法
将uart取得的数据,经过入栈存入到一个数据表中,然后用pop出栈进行数据处理
大体做法是:
要进行传输的数据必须格式化,例如设置数据头和数据尾来判断一帧完整的数据.
数据的头和尾之间是有效数据,可以包含数据的定义和数据本身
单片机接受到数据后,先存入到
HAL_UART_Receive_IT(&huart1, que._data, QUEUE_max_size);
这句话的que._data数据表中,这个数据表可以设置的长一点,不会溢出就行
然后写一个程序处理这个里面的数据,第一步就是查找判断这个数据是不是按照上面的数据格式
的数据,如果不是则舍弃,否则,按照你的数据规则取得这个有效的数据例如queue_find_cmd(cmd_buffer,30),其中cmd_buffer里面就是得到的数据.
然后可以依照规则将每位进行分解处理,例如cmd_buffer[1]=0x00表示这次传输的是数字,=0x01则表示传输的是字符串,然后cmd_buffer[2]+(cmd_buffer[3]<<8)+(cmd_buffer[4]<<16)+(cmd_buffer[5]<<24).
这样表示后面的是连续32位数据,呵呵
2楼继续.

祝贺版主,希望持续的关注,能给你继续努力的动力

新手交流admin 回复了问题 • 1 人关注 • 2 个回复 • 693 次浏览 • 2014-10-21 10:54 • 来自相关话题

TIM定时器再次研究,其实一直都是只知道用,不知道道理,导致后面出了好多问题,烦

经验分享admin 发表了文章 • 12 个评论 • 18238 次浏览 • 2014-10-20 09:59 • 来自相关话题

只研究stm32cube生成的代码里面的TIM定时器的用法.
这次务必搞懂,不留后遗症,一直知道怎么用,但是还是不了解为什么,导致问题多多,以此借鉴!






1: 生成了一个定时一秒的代码,如下:
/ TIM3 init function /
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);

}
为什么呢?以前是按照我总结的写的,这次原理要弄懂.tnnd
htim3.Init.Prescaler = 8399; 这个是分频数,就是将时钟分频使频率降低,额,我是这样理解的
上面用的定时器3,连接的是APB1时钟,而我的时钟是:





所以当前的频率是:时钟频率/(分频数+1)=84000000/8400=10000HZ
即每次定时器自加1时间为1/10000=0.0001s
htim3.Init.Period = 9999; 这个意思是:自动重载值,可以理解为当从0开始加到这个值的时候,定时器中断一次
所以从0加到9999共10000次,所需时间=10000*0.0001=1s
定时时间1s.
好了,2楼回复中继续研究定时器其他参数. 查看全部
只研究stm32cube生成的代码里面的TIM定时器的用法.
这次务必搞懂,不留后遗症,一直知道怎么用,但是还是不了解为什么,导致问题多多,以此借鉴!

1345217050_8286.JPG


1: 生成了一个定时一秒的代码,如下:
/ TIM3 init function /
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);

}
为什么呢?以前是按照我总结的写的,这次原理要弄懂.tnnd
htim3.Init.Prescaler = 8399; 这个是分频数,就是将时钟分频使频率降低,额,我是这样理解的
上面用的定时器3,连接的是APB1时钟,而我的时钟是:

QQ图片20141020095418.jpg

所以当前的频率是:时钟频率/(分频数+1)=84000000/8400=10000HZ
即每次定时器自加1时间为1/10000=0.0001s
htim3.Init.Period = 9999; 这个意思是:自动重载值,可以理解为当从0开始加到这个值的时候,定时器中断一次
所以从0加到9999共10000次,所需时间=10000*0.0001=1s
定时时间1s.
好了,2楼回复中继续研究定时器其他参数.

(分享)经典的按键程序,用状态机写的,支持长按双按等

经验分享admin 发表了文章 • 2 个评论 • 2785 次浏览 • 2014-10-16 14:08 • 来自相关话题

转自阿莫论坛,感谢AbnerSmith提供.
支持短按、长按、双短按、短长按以及多按键同时按下的按键程序,用状态机写的,和大家分享一下。

按键的头文件在下方


/**********************************************************************************************
* File Name : bsp_key.c
* Required Perconditions :
* Called Functions : TIM_IsExpired(),TIM_GetTimestamp()
* Author : Abner
* Created : 02/09/2014
* Updated : 28/09/2014
*
* ===========================================================================================
* @attention
* KeyValue : [15..13]->KeyState,[12..9]->Reserved,[8..3]->KeyID,[2..0]->KeyEvent
* KeyState = keyval & 0xE000,KeyID = keyval & 0x01F8,KeyEvent = keyval & 0x0007,
* bsp_timer.h and bsp_key.h ought to be included
* Call Key_Init() before Key_GetValue()
*
*
* <------ Add to Group BSP/HAL/SRC ------->
* ===========================================================================================
* @updated
* 1.Deleted some Key_State
* 2.Add the Current KeyState(KEY_STATE_INIT or KEY_STATE_UNRELEASED) to rtnval
* 3.Replace defines for KeyEventime(in bsp_key.h) with Function(Key_SetEventTime)
* 4.Define KEY_x_EffectiveLevel in header_file to make it convenient to modify it
* so it can apply to other boards.
* 5.Support 6 Independent_Keys(Max upto 10,but need modify Key_Init() & Key_GetID())
* 6.MultiKeyID were Deleted
* 7.Fix bug : When you release other key during MultiPressed state,return KeyID won't
* reflect this changes.
*
*********************************************************************************************/

/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/

#include "bsp_key.h"
#include "bsp_timer.h"


/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/


/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/



/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static u32 KeyTime_Jitter = 5 ; //Time for excluding Jiteter interference
static u32 KeyTime_Interval = 400 ; //Time for confirming status had swtiched
static u32 KeyTime_Long = 800 ; //Time for confirming long pressed
static u32 KeyTime_Double = 300 ; //Time between double pressed

/*
*********************************************************************************************************
*********************************************************************************************************
** GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/

/*
*********************************************************************************************************
* Key_Init()
*
* Description : Initialize GPIO Pin,Speed,Mode for Key.
*
* Argument(s) : None.
*
* Return(s) : None.
*
* Note(s) : (1) Key's GPIO(Pin,Speed,Mode) is defined in the bsp_key.h.
*********************************************************************************************************
*/

void
Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

#if (KEY_SUPPORTNUM > 0)
RCC_APB2PeriphClockCmd (KEY_0_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_0_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_0_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_0_GPIO_Mode;
GPIO_Init (KEY_0_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 1)
RCC_APB2PeriphClockCmd (KEY_1_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_1_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_1_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_1_GPIO_Mode;
GPIO_Init (KEY_1_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 2)
RCC_APB2PeriphClockCmd (KEY_2_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_2_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_2_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_2_GPIO_Mode;
GPIO_Init (KEY_2_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 3)
RCC_APB2PeriphClockCmd (KEY_3_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_3_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_3_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_3_GPIO_Mode;
GPIO_Init (KEY_3_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 4)
RCC_APB2PeriphClockCmd (KEY_4_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_4_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_4_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_4_GPIO_Mode;
GPIO_Init (KEY_4_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 5)
RCC_APB2PeriphClockCmd (KEY_0_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_5_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_5_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_5_GPIO_Mode ;
GPIO_Init (KEY_5_GPIO_Port,&GPIO_InitStructure );

#endif
}


/*
*********************************************************************************************************
* Key_GetID()
*
* Description : Get pressed Key(s)'(s) ID(s).
*
* Argument(s) : None.
*
* Return(s) : Pressed Key(s)'(s) ID(s).
*
* Note(s) : (1) Key's EffectiveLevel is defined in the bsp_key.h.
*********************************************************************************************************
*/

KeyID_Enum_t
Key_GetID(void)
{
KeyID_Enum_t KeyIDTmp = KEY_ID_NONE ;

#if (KEY_SUPPORTNUM > 0)&&(USE_WKUP_PA0 == 0)
if(GPIO_ReadInputDataBit (KEY_0_GPIO_Port ,KEY_0_GPIO_Pin ) == KEY_0_EffectiveLevel)
KeyIDTmp |= KEY_ID_0;
#endif

#if (KEY_SUPPORTNUM > 1)
if(GPIO_ReadInputDataBit (KEY_1_GPIO_Port ,KEY_1_GPIO_Pin ) == KEY_1_EffectiveLevel)
KeyIDTmp |= KEY_ID_1;
#endif

#if (KEY_SUPPORTNUM > 2)
if(GPIO_ReadInputDataBit (KEY_2_GPIO_Port ,KEY_2_GPIO_Pin ) == KEY_2_EffectiveLevel)
KeyIDTmp |= KEY_ID_2;
#endif

#if (KEY_SUPPORTNUM > 3)
if(GPIO_ReadInputDataBit (KEY_3_GPIO_Port ,KEY_3_GPIO_Pin ) == KEY_3_EffectiveLevel)
KeyIDTmp |= KEY_ID_3;
#endif

#if (KEY_SUPPORTNUM > 4)
if(GPIO_ReadInputDataBit (KEY_4_GPIO_Port ,KEY_4_GPIO_Pin ) == KEY_4_EffectiveLevel)
KeyIDTmp |= KEY_ID_4;
#endif

#if (KEY_SUPPORTNUM > 5)
if(GPIO_ReadInputDataBit (KEY_5_GPIO_Port ,KEY_5_GPIO_Pin ) == KEY_5_EffectiveLevel)
KeyIDTmp |= KEY_ID_5;
#endif

return KeyIDTmp;
}


/*
*********************************************************************************************************
* Key_GetValue()
*
* Description : Get pressed Key's ID,and the first event key's event and status.
*
* Argument(s) : None.
*
* Return(s) : @ Description.
*
* Note(s) : (1) wait to update to support for getting each key's event and status independently.
* (2) KeyState = keyval & 0xE000,KeyID = keyval & 0x01F8,KeyEvent = keyval & 0x0007.
* (3) the time for Jitter and others is based on set Timestamp period to 1 ms (@bsp_timer)
*********************************************************************************************************
*/

u16
Key_GetValue(void)
{
static KeyAction_Struct_t KeyAction = {KEY_ID_NONE ,KEY_STATE_INIT ,KEY_EVENT_NONE ,0,0,0};
static u16 KeyValue = KEY_STATE_INIT | KEY_ID_NONE | KEY_EVENT_NONE;

static KeyID_Enum_t KeyIDTmp = KEY_ID_NONE ;

static u16 LastKeyValue = KEY_STATE_INIT | KEY_ID_NONE | KEY_EVENT_NONE ;

KeyAction .KeyID = Key_GetID() ;

switch(KeyAction .KeyState )
{
case KEY_STATE_INIT :
{
if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_JITTER ;
KeyAction .KeyJitterTime = TIM_GetSTime ();
}
}break;

case KEY_STATE_JITTER :
{
if(TIM_IsExpired (KeyAction .KeyJitterTime + KeyTime_Jitter ))
{
if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyIDTmp = KeyAction .KeyID ;
KeyAction .KeyState = KEY_STATE_PRESSED ;
KeyAction .KeyPressedTime = TIM_GetSTime ();
}
else
{
KeyAction .KeyID = KEY_ID_NONE ;
KeyAction .KeyState = KEY_STATE_INIT ;
}
}
}break;

case KEY_STATE_PRESSED :
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INTERIM1 ;
KeyAction .KeyReleasedTime = TIM_GetSTime ();
}

if(TIM_IsExpired (KeyAction .KeyPressedTime + KeyTime_Long ) )
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INIT ;
}
else
{
KeyAction .KeyState = KEY_STATE_UNRELEASED ;
}
LastKeyValue = KeyAction .KeyState | KeyIDTmp | KEY_EVENT_LONG ;

return LastKeyValue ;
}
}break;

case KEY_STATE_INTERIM1 :
{
if(TIM_IsExpired (KeyAction .KeyReleasedTime + KeyTime_Interval ))
{
KeyAction .KeyState = KEY_STATE_JITTER ;
}

if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyIDTmp = KeyAction .KeyID ;
KeyAction .KeyPressedTime = TIM_GetSTime ();
KeyAction .KeyState = KEY_STATE_INTERIM2 ;
}
else
{
if(TIM_IsExpired (KeyAction .KeyReleasedTime + KeyTime_Double ))
{
KeyAction .KeyState = KEY_STATE_INIT ;
LastKeyValue = KEY_STATE_INIT | KeyIDTmp | KEY_EVENT_SHORT ;
return LastKeyValue ;
}
}
}break;

case KEY_STATE_INTERIM2 :
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INIT ;
LastKeyValue = KEY_STATE_INIT | KeyIDTmp | KEY_EVENT_DOUBLESHORT ;
return LastKeyValue ;
}
else
{
if(TIM_IsExpired (KeyAction .KeyPressedTime + KeyTime_Long ))
{
KeyAction .KeyState = KEY_STATE_UNRELEASED ;
LastKeyValue = KEY_STATE_UNRELEASED | KeyIDTmp | KEY_EVENT_SHORTLONG ;
return LastKeyValue ;
}
}
}break;

case KEY_STATE_UNRELEASED :
{
if(KeyAction .KeyID == KEY_ID_NONE)
{
KeyAction .KeyState = KEY_STATE_INIT ;
}
else
{
KeyIDTmp = KeyAction .KeyID ;
return KEY_STATE_UNRELEASED | KeyIDTmp | (LastKeyValue & 0x0007 ) ;
}
}break;

default :
break;
}

return KeyValue ;
}


/**********************************************************************************************
* Function Name : Key_SetEventTime
* Function Prototype : void Key_SetEventTime(u32 NewKeyTime_Jitter ,
* u32 NewKeyTime_Interval ,
* u32 NewKeyTime_Long ,
* u32 NewKeyTime_Double )
* Behavior Description : Set KeyTime_Jitter,KeyTime_Interval,KeyTime_Long,Time_Double
* Input Parameter : NewKeyTime_Jitter,NewKeyTime_Interval,
* NewKeyTime_Long,NewTime_Double
*
* Output Parameter : None
* Return Parameter : None
* Required Perconditions : None
* Called Functions : None
*
* ===========================================================================================
* @ attention
*
*
*
*
*********************************************************************************************/

/*
*********************************************************************************************************
* Key_SetEventTime(KeyTime_Jitter,...)
*
* Description : Set JitterTimer, IntervalTime, LongTime, and DoubleTime.
*
* Argument(s) : NewKeyTime_Jitter,NewKeyTime_Interval,NewKeyTime_Long,NewKeyTime_Double.
*
* Return(s) : None.
*
* Note(s) : (1) you'd better not to call this function
*********************************************************************************************************
*/

void Key_SetEventTime(u32 NewKeyTime_Jitter ,
u32 NewKeyTime_Interval ,
u32 NewKeyTime_Long ,
u32 NewKeyTime_Double )
{
KeyTime_Jitter = NewKeyTime_Jitter ;
KeyTime_Interval = NewKeyTime_Interval ;
KeyTime_Long = NewKeyTime_Long ;
KeyTime_Double = NewKeyTime_Double ;
}




/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static u32 Timestamp ;

/*
*********************************************************************************************************
*********************************************************************************************************
** GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/

/*
*********************************************************************************************************
* Block : Timestamp
* Block Description : TIM7 configured to provide functions TIM_GetSTime() and TIM_IsExpired()
*
* ======================================================================================================
* @ attention
* Recommend Counter frequency is 1kHz ,period is 1mS.
*
*
*********************************************************************************************************
*/

void
TIM_Stamp_Init(u16 arr,u16 psc)//recommend : arr = 719 ,psc = 99 --> 1mS
{
NVIC_InitTypeDef NVIC_InitStructure ;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM7 ,ENABLE );

TIM_TimeBaseStructure .TIM_Period = arr ;
TIM_TimeBaseStructure .TIM_Prescaler = psc ;
TIM_TimeBaseStructure .TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_TimeBaseStructure .TIM_CounterMode = TIM_CounterMode_Up ;
TIM_TimeBaseInit (TIM7 ,&TIM_TimeBaseStructure );

NVIC_InitStructure .NVIC_IRQChannel = TIM7_IRQn ;
NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 1 ;
NVIC_InitStructure .NVIC_IRQChannelSubPriority = 0 ;
NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE ;
NVIC_Init (&NVIC_InitStructure );

TIM_ITConfig (TIM7 ,TIM_IT_Update ,ENABLE );
TIM_Cmd (TIM7 ,ENABLE );
}

u32
TIM_GetSTime(void)
{
return Timestamp ;
}

u8
TIM_IsExpired(u32 PeriodBased)
{
u32 time_now = Timestamp ;

if(time_now > PeriodBased )
{
if((time_now - PeriodBased ) < 0x80000000)
return 1;
else
return 0;
}
else
{
if((PeriodBased - time_now ) > 0x80000000)
return 1;
else
return 0;
}
}

void
TIM7_IRQHandler(void)
{
Timestamp ++ ;
TIM_ClearITPendingBit (TIM7,TIM_IT_Update );
}




/**********************************************************************************************
* File Name : bsp_key.h
* Required Perconditions :
* Called Functions :
* Author : Abner
* Created : 02/09/2014
* Updated : 28/09/2014
*
* ===========================================================================================
* @attention
*
*
*
* <------ Add to Group BSP/HAL/INC ------->
* ===========================================================================================
* @updated
*
*
*
*********************************************************************************************/

#ifndef _BSP_KEY_H
#define _BSP_KEY_H

/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/

#include "stm32f10x_conf.h"


/*
*********************************************************************************************************
* DEFINES
*********************************************************************************************************
*/

//KEY_SUPPORTNUM : Defualt->4,Max->6
//Support upto 10,but need modify bsp_key.c
#define KEY_SUPPORTNUM (4)

#if KEY_SUPPORTNUM > 6
#error "Max support keys is six"
#endif

/*
*********************************************************************************************************
* Block : hardware define
* Block Description : define GPIO_Port,GPIO_Pin,GPIO_RCC_Periph,GPIO_Mode for each Key
*
* =======================================================================================================
* @ attention
* It's of importance for modify GPIO_Mode after (GPIO_Port,GPIO_Pin,GPIO_RCC_Periph)
* for GPIOA to GPIOG , GPIO_RCC_Periph is always RCC_APB2Periph_GPIOx(x coulde be A to G)
*
*********************************************************************************************************
*/

/*
#define KEY_UP KEY_0
#define KEY_DOWN KEY_1
#define KEY_LEFT KEY_2
#define KEY_RIGHT KEY_3
#define KEY_ENTER KEY_5
#define KEY_ESC KEY_6
*/

#if (KEY_SUPPORTNUM > 0)&&(USE_WKUP_PA0 == 0)

#define KEY_0_GPIO_Port GPIOA
#define KEY_0_GPIO_Pin GPIO_Pin_0
#define KEY_0_GPIO_RCC_Periph RCC_APB2Periph_GPIOA
#define KEY_0_GPIO_Speed GPIO_Speed_50MHz

#define KEY_0_GPIO_Mode GPIO_Mode_IPD
#define KEY_0_EffectiveLevel 1

#endif

#if (KEY_SUPPORTNUM > 1)

#define KEY_1_GPIO_Port GPIOE
#define KEY_1_GPIO_Pin GPIO_Pin_3
#define KEY_1_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_1_GPIO_Speed GPIO_Speed_50MHz

#define KEY_1_GPIO_Mode GPIO_Mode_IPU
#define KEY_1_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 2)

#define KEY_2_GPIO_Port GPIOE
#define KEY_2_GPIO_Pin GPIO_Pin_2
#define KEY_2_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_2_GPIO_Speed GPIO_Speed_50MHz

#define KEY_2_GPIO_Mode GPIO_Mode_IPU
#define KEY_2_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 3)

#define KEY_3_GPIO_Port GPIOE
#define KEY_3_GPIO_Pin GPIO_Pin_4
#define KEY_3_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_3_GPIO_Speed GPIO_Speed_50MHz

#define KEY_3_GPIO_Mode GPIO_Mode_IPU
#define KEY_3_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 4)

#define KEY_4_GPIO_Port GPIOE
#define KEY_4_GPIO_Pin GPIO_Pin_4
#define KEY_4_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_4_GPIO_Speed GPIO_Speed_50MHz

#define KEY_4_GPIO_Mode GPIO_Mode_IPU
#define KEY_4_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 5)

#define KEY_5_GPIO_Port GPIOE
#define KEY_5_GPIO_Pin GPIO_Pin_4
#define KEY_5_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_5_GPIO_Speed GPIO_Speed_50MHz

#define KEY_5_GPIO_Mode GPIO_Mode_IPU
#define KEY_5_EffectiveLevel 0

#endif


/*
*********************************************************************************************************
* TYPE DEFINES
*********************************************************************************************************
*/

typedef enum {
KEY_ID_NONE = 0x0000,

KEY_ID_0 = 0x0008,
KEY_ID_1 = 0x0010,
KEY_ID_2 = 0x0020,
KEY_ID_3 = 0x0040,
KEY_ID_4 = 0x0080,
KEY_ID_5 = 0x0100,

KEY_ID_Multi ,

}KeyID_Enum_t;

typedef enum {
KEY_STATE_INIT = 0x0000,
KEY_STATE_JITTER = 0x2000,
KEY_STATE_PRESSED = 0x4000,
KEY_STATE_INTERIM1 = 0x6000,
KEY_STATE_INTERIM2 = 0x8000,
KEY_STATE_UNRELEASED = 0xA000,

}KeyState_Enum_t;

typedef enum {
KEY_EVENT_NONE = 0x0000,
KEY_EVENT_SHORT = 0x0001,
KEY_EVENT_LONG = 0x0002,
KEY_EVENT_DOUBLESHORT = 0x0003,
KEY_EVENT_SHORTLONG = 0x0004,

}KeyEvent_Enum_t;

typedef struct {
KeyID_Enum_t KeyID;
KeyState_Enum_t KeyState;
KeyEvent_Enum_t KeyEvent;
u32 KeyJitterTime;
u32 KeyPressedTime;
u32 KeyReleasedTime;

}KeyAction_Struct_t;


/*
*********************************************************************************************************
* FUNCTION PROTOTYPES
*********************************************************************************************************
*/

void Key_Init (void);
KeyID_Enum_t Key_GetID (void);
u16 Key_GetValue (void);

void Key_SetEventTime ( u32 NewKeyTime_Jitter ,
u32 NewKeyTime_Interval ,
u32 NewKeyTime_Long ,
u32 NewKeyTime_Double ) ;

#endif 查看全部
转自阿莫论坛,感谢AbnerSmith提供.
支持短按、长按、双短按、短长按以及多按键同时按下的按键程序,用状态机写的,和大家分享一下。

按键的头文件在下方


/**********************************************************************************************
* File Name : bsp_key.c
* Required Perconditions :
* Called Functions : TIM_IsExpired(),TIM_GetTimestamp()
* Author : Abner
* Created : 02/09/2014
* Updated : 28/09/2014
*
* ===========================================================================================
* @attention
* KeyValue : [15..13]->KeyState,[12..9]->Reserved,[8..3]->KeyID,[2..0]->KeyEvent
* KeyState = keyval & 0xE000,KeyID = keyval & 0x01F8,KeyEvent = keyval & 0x0007,
* bsp_timer.h and bsp_key.h ought to be included
* Call Key_Init() before Key_GetValue()
*
*
* <------ Add to Group BSP/HAL/SRC ------->
* ===========================================================================================
* @updated
* 1.Deleted some Key_State
* 2.Add the Current KeyState(KEY_STATE_INIT or KEY_STATE_UNRELEASED) to rtnval
* 3.Replace defines for KeyEventime(in bsp_key.h) with Function(Key_SetEventTime)
* 4.Define KEY_x_EffectiveLevel in header_file to make it convenient to modify it
* so it can apply to other boards.
* 5.Support 6 Independent_Keys(Max upto 10,but need modify Key_Init() & Key_GetID())
* 6.MultiKeyID were Deleted
* 7.Fix bug : When you release other key during MultiPressed state,return KeyID won't
* reflect this changes.
*
*********************************************************************************************/

/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/

#include "bsp_key.h"
#include "bsp_timer.h"


/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/


/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/



/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static u32 KeyTime_Jitter = 5 ; //Time for excluding Jiteter interference
static u32 KeyTime_Interval = 400 ; //Time for confirming status had swtiched
static u32 KeyTime_Long = 800 ; //Time for confirming long pressed
static u32 KeyTime_Double = 300 ; //Time between double pressed

/*
*********************************************************************************************************
*********************************************************************************************************
** GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/

/*
*********************************************************************************************************
* Key_Init()
*
* Description : Initialize GPIO Pin,Speed,Mode for Key.
*
* Argument(s) : None.
*
* Return(s) : None.
*
* Note(s) : (1) Key's GPIO(Pin,Speed,Mode) is defined in the bsp_key.h.
*********************************************************************************************************
*/

void
Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

#if (KEY_SUPPORTNUM > 0)
RCC_APB2PeriphClockCmd (KEY_0_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_0_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_0_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_0_GPIO_Mode;
GPIO_Init (KEY_0_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 1)
RCC_APB2PeriphClockCmd (KEY_1_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_1_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_1_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_1_GPIO_Mode;
GPIO_Init (KEY_1_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 2)
RCC_APB2PeriphClockCmd (KEY_2_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_2_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_2_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_2_GPIO_Mode;
GPIO_Init (KEY_2_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 3)
RCC_APB2PeriphClockCmd (KEY_3_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_3_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_3_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_3_GPIO_Mode;
GPIO_Init (KEY_3_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 4)
RCC_APB2PeriphClockCmd (KEY_4_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_4_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_4_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_4_GPIO_Mode;
GPIO_Init (KEY_4_GPIO_Port,&GPIO_InitStructure );

#endif

#if (KEY_SUPPORTNUM > 5)
RCC_APB2PeriphClockCmd (KEY_0_GPIO_RCC_Periph ,ENABLE );

GPIO_InitStructure .GPIO_Pin = KEY_5_GPIO_Pin ;
GPIO_InitStructure .GPIO_Speed = KEY_5_GPIO_Speed ;
GPIO_InitStructure .GPIO_Mode = KEY_5_GPIO_Mode ;
GPIO_Init (KEY_5_GPIO_Port,&GPIO_InitStructure );

#endif
}


/*
*********************************************************************************************************
* Key_GetID()
*
* Description : Get pressed Key(s)'(s) ID(s).
*
* Argument(s) : None.
*
* Return(s) : Pressed Key(s)'(s) ID(s).
*
* Note(s) : (1) Key's EffectiveLevel is defined in the bsp_key.h.
*********************************************************************************************************
*/

KeyID_Enum_t
Key_GetID(void)
{
KeyID_Enum_t KeyIDTmp = KEY_ID_NONE ;

#if (KEY_SUPPORTNUM > 0)&&(USE_WKUP_PA0 == 0)
if(GPIO_ReadInputDataBit (KEY_0_GPIO_Port ,KEY_0_GPIO_Pin ) == KEY_0_EffectiveLevel)
KeyIDTmp |= KEY_ID_0;
#endif

#if (KEY_SUPPORTNUM > 1)
if(GPIO_ReadInputDataBit (KEY_1_GPIO_Port ,KEY_1_GPIO_Pin ) == KEY_1_EffectiveLevel)
KeyIDTmp |= KEY_ID_1;
#endif

#if (KEY_SUPPORTNUM > 2)
if(GPIO_ReadInputDataBit (KEY_2_GPIO_Port ,KEY_2_GPIO_Pin ) == KEY_2_EffectiveLevel)
KeyIDTmp |= KEY_ID_2;
#endif

#if (KEY_SUPPORTNUM > 3)
if(GPIO_ReadInputDataBit (KEY_3_GPIO_Port ,KEY_3_GPIO_Pin ) == KEY_3_EffectiveLevel)
KeyIDTmp |= KEY_ID_3;
#endif

#if (KEY_SUPPORTNUM > 4)
if(GPIO_ReadInputDataBit (KEY_4_GPIO_Port ,KEY_4_GPIO_Pin ) == KEY_4_EffectiveLevel)
KeyIDTmp |= KEY_ID_4;
#endif

#if (KEY_SUPPORTNUM > 5)
if(GPIO_ReadInputDataBit (KEY_5_GPIO_Port ,KEY_5_GPIO_Pin ) == KEY_5_EffectiveLevel)
KeyIDTmp |= KEY_ID_5;
#endif

return KeyIDTmp;
}


/*
*********************************************************************************************************
* Key_GetValue()
*
* Description : Get pressed Key's ID,and the first event key's event and status.
*
* Argument(s) : None.
*
* Return(s) : @ Description.
*
* Note(s) : (1) wait to update to support for getting each key's event and status independently.
* (2) KeyState = keyval & 0xE000,KeyID = keyval & 0x01F8,KeyEvent = keyval & 0x0007.
* (3) the time for Jitter and others is based on set Timestamp period to 1 ms (@bsp_timer)
*********************************************************************************************************
*/

u16
Key_GetValue(void)
{
static KeyAction_Struct_t KeyAction = {KEY_ID_NONE ,KEY_STATE_INIT ,KEY_EVENT_NONE ,0,0,0};
static u16 KeyValue = KEY_STATE_INIT | KEY_ID_NONE | KEY_EVENT_NONE;

static KeyID_Enum_t KeyIDTmp = KEY_ID_NONE ;

static u16 LastKeyValue = KEY_STATE_INIT | KEY_ID_NONE | KEY_EVENT_NONE ;

KeyAction .KeyID = Key_GetID() ;

switch(KeyAction .KeyState )
{
case KEY_STATE_INIT :
{
if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_JITTER ;
KeyAction .KeyJitterTime = TIM_GetSTime ();
}
}break;

case KEY_STATE_JITTER :
{
if(TIM_IsExpired (KeyAction .KeyJitterTime + KeyTime_Jitter ))
{
if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyIDTmp = KeyAction .KeyID ;
KeyAction .KeyState = KEY_STATE_PRESSED ;
KeyAction .KeyPressedTime = TIM_GetSTime ();
}
else
{
KeyAction .KeyID = KEY_ID_NONE ;
KeyAction .KeyState = KEY_STATE_INIT ;
}
}
}break;

case KEY_STATE_PRESSED :
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INTERIM1 ;
KeyAction .KeyReleasedTime = TIM_GetSTime ();
}

if(TIM_IsExpired (KeyAction .KeyPressedTime + KeyTime_Long ) )
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INIT ;
}
else
{
KeyAction .KeyState = KEY_STATE_UNRELEASED ;
}
LastKeyValue = KeyAction .KeyState | KeyIDTmp | KEY_EVENT_LONG ;

return LastKeyValue ;
}
}break;

case KEY_STATE_INTERIM1 :
{
if(TIM_IsExpired (KeyAction .KeyReleasedTime + KeyTime_Interval ))
{
KeyAction .KeyState = KEY_STATE_JITTER ;
}

if(KeyAction .KeyID != KEY_ID_NONE )
{
KeyIDTmp = KeyAction .KeyID ;
KeyAction .KeyPressedTime = TIM_GetSTime ();
KeyAction .KeyState = KEY_STATE_INTERIM2 ;
}
else
{
if(TIM_IsExpired (KeyAction .KeyReleasedTime + KeyTime_Double ))
{
KeyAction .KeyState = KEY_STATE_INIT ;
LastKeyValue = KEY_STATE_INIT | KeyIDTmp | KEY_EVENT_SHORT ;
return LastKeyValue ;
}
}
}break;

case KEY_STATE_INTERIM2 :
{
if(KeyAction .KeyID == KEY_ID_NONE )
{
KeyAction .KeyState = KEY_STATE_INIT ;
LastKeyValue = KEY_STATE_INIT | KeyIDTmp | KEY_EVENT_DOUBLESHORT ;
return LastKeyValue ;
}
else
{
if(TIM_IsExpired (KeyAction .KeyPressedTime + KeyTime_Long ))
{
KeyAction .KeyState = KEY_STATE_UNRELEASED ;
LastKeyValue = KEY_STATE_UNRELEASED | KeyIDTmp | KEY_EVENT_SHORTLONG ;
return LastKeyValue ;
}
}
}break;

case KEY_STATE_UNRELEASED :
{
if(KeyAction .KeyID == KEY_ID_NONE)
{
KeyAction .KeyState = KEY_STATE_INIT ;
}
else
{
KeyIDTmp = KeyAction .KeyID ;
return KEY_STATE_UNRELEASED | KeyIDTmp | (LastKeyValue & 0x0007 ) ;
}
}break;

default :
break;
}

return KeyValue ;
}


/**********************************************************************************************
* Function Name : Key_SetEventTime
* Function Prototype : void Key_SetEventTime(u32 NewKeyTime_Jitter ,
* u32 NewKeyTime_Interval ,
* u32 NewKeyTime_Long ,
* u32 NewKeyTime_Double )
* Behavior Description : Set KeyTime_Jitter,KeyTime_Interval,KeyTime_Long,Time_Double
* Input Parameter : NewKeyTime_Jitter,NewKeyTime_Interval,
* NewKeyTime_Long,NewTime_Double
*
* Output Parameter : None
* Return Parameter : None
* Required Perconditions : None
* Called Functions : None
*
* ===========================================================================================
* @ attention
*
*
*
*
*********************************************************************************************/

/*
*********************************************************************************************************
* Key_SetEventTime(KeyTime_Jitter,...)
*
* Description : Set JitterTimer, IntervalTime, LongTime, and DoubleTime.
*
* Argument(s) : NewKeyTime_Jitter,NewKeyTime_Interval,NewKeyTime_Long,NewKeyTime_Double.
*
* Return(s) : None.
*
* Note(s) : (1) you'd better not to call this function
*********************************************************************************************************
*/

void Key_SetEventTime(u32 NewKeyTime_Jitter ,
u32 NewKeyTime_Interval ,
u32 NewKeyTime_Long ,
u32 NewKeyTime_Double )
{
KeyTime_Jitter = NewKeyTime_Jitter ;
KeyTime_Interval = NewKeyTime_Interval ;
KeyTime_Long = NewKeyTime_Long ;
KeyTime_Double = NewKeyTime_Double ;
}




/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static u32 Timestamp ;

/*
*********************************************************************************************************
*********************************************************************************************************
** GLOBAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/

/*
*********************************************************************************************************
* Block : Timestamp
* Block Description : TIM7 configured to provide functions TIM_GetSTime() and TIM_IsExpired()
*
* ======================================================================================================
* @ attention
* Recommend Counter frequency is 1kHz ,period is 1mS.
*
*
*********************************************************************************************************
*/

void
TIM_Stamp_Init(u16 arr,u16 psc)//recommend : arr = 719 ,psc = 99 --> 1mS
{
NVIC_InitTypeDef NVIC_InitStructure ;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM7 ,ENABLE );

TIM_TimeBaseStructure .TIM_Period = arr ;
TIM_TimeBaseStructure .TIM_Prescaler = psc ;
TIM_TimeBaseStructure .TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_TimeBaseStructure .TIM_CounterMode = TIM_CounterMode_Up ;
TIM_TimeBaseInit (TIM7 ,&TIM_TimeBaseStructure );

NVIC_InitStructure .NVIC_IRQChannel = TIM7_IRQn ;
NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 1 ;
NVIC_InitStructure .NVIC_IRQChannelSubPriority = 0 ;
NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE ;
NVIC_Init (&NVIC_InitStructure );

TIM_ITConfig (TIM7 ,TIM_IT_Update ,ENABLE );
TIM_Cmd (TIM7 ,ENABLE );
}

u32
TIM_GetSTime(void)
{
return Timestamp ;
}

u8
TIM_IsExpired(u32 PeriodBased)
{
u32 time_now = Timestamp ;

if(time_now > PeriodBased )
{
if((time_now - PeriodBased ) < 0x80000000)
return 1;
else
return 0;
}
else
{
if((PeriodBased - time_now ) > 0x80000000)
return 1;
else
return 0;
}
}

void
TIM7_IRQHandler(void)
{
Timestamp ++ ;
TIM_ClearITPendingBit (TIM7,TIM_IT_Update );
}




/**********************************************************************************************
* File Name : bsp_key.h
* Required Perconditions :
* Called Functions :
* Author : Abner
* Created : 02/09/2014
* Updated : 28/09/2014
*
* ===========================================================================================
* @attention
*
*
*
* <------ Add to Group BSP/HAL/INC ------->
* ===========================================================================================
* @updated
*
*
*
*********************************************************************************************/

#ifndef _BSP_KEY_H
#define _BSP_KEY_H

/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/

#include "stm32f10x_conf.h"


/*
*********************************************************************************************************
* DEFINES
*********************************************************************************************************
*/

//KEY_SUPPORTNUM : Defualt->4,Max->6
//Support upto 10,but need modify bsp_key.c
#define KEY_SUPPORTNUM (4)

#if KEY_SUPPORTNUM > 6
#error "Max support keys is six"
#endif

/*
*********************************************************************************************************
* Block : hardware define
* Block Description : define GPIO_Port,GPIO_Pin,GPIO_RCC_Periph,GPIO_Mode for each Key
*
* =======================================================================================================
* @ attention
* It's of importance for modify GPIO_Mode after (GPIO_Port,GPIO_Pin,GPIO_RCC_Periph)
* for GPIOA to GPIOG , GPIO_RCC_Periph is always RCC_APB2Periph_GPIOx(x coulde be A to G)
*
*********************************************************************************************************
*/

/*
#define KEY_UP KEY_0
#define KEY_DOWN KEY_1
#define KEY_LEFT KEY_2
#define KEY_RIGHT KEY_3
#define KEY_ENTER KEY_5
#define KEY_ESC KEY_6
*/

#if (KEY_SUPPORTNUM > 0)&&(USE_WKUP_PA0 == 0)

#define KEY_0_GPIO_Port GPIOA
#define KEY_0_GPIO_Pin GPIO_Pin_0
#define KEY_0_GPIO_RCC_Periph RCC_APB2Periph_GPIOA
#define KEY_0_GPIO_Speed GPIO_Speed_50MHz

#define KEY_0_GPIO_Mode GPIO_Mode_IPD
#define KEY_0_EffectiveLevel 1

#endif

#if (KEY_SUPPORTNUM > 1)

#define KEY_1_GPIO_Port GPIOE
#define KEY_1_GPIO_Pin GPIO_Pin_3
#define KEY_1_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_1_GPIO_Speed GPIO_Speed_50MHz

#define KEY_1_GPIO_Mode GPIO_Mode_IPU
#define KEY_1_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 2)

#define KEY_2_GPIO_Port GPIOE
#define KEY_2_GPIO_Pin GPIO_Pin_2
#define KEY_2_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_2_GPIO_Speed GPIO_Speed_50MHz

#define KEY_2_GPIO_Mode GPIO_Mode_IPU
#define KEY_2_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 3)

#define KEY_3_GPIO_Port GPIOE
#define KEY_3_GPIO_Pin GPIO_Pin_4
#define KEY_3_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_3_GPIO_Speed GPIO_Speed_50MHz

#define KEY_3_GPIO_Mode GPIO_Mode_IPU
#define KEY_3_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 4)

#define KEY_4_GPIO_Port GPIOE
#define KEY_4_GPIO_Pin GPIO_Pin_4
#define KEY_4_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_4_GPIO_Speed GPIO_Speed_50MHz

#define KEY_4_GPIO_Mode GPIO_Mode_IPU
#define KEY_4_EffectiveLevel 0

#endif

#if (KEY_SUPPORTNUM > 5)

#define KEY_5_GPIO_Port GPIOE
#define KEY_5_GPIO_Pin GPIO_Pin_4
#define KEY_5_GPIO_RCC_Periph RCC_APB2Periph_GPIOE
#define KEY_5_GPIO_Speed GPIO_Speed_50MHz

#define KEY_5_GPIO_Mode GPIO_Mode_IPU
#define KEY_5_EffectiveLevel 0

#endif


/*
*********************************************************************************************************
* TYPE DEFINES
*********************************************************************************************************
*/

typedef enum {
KEY_ID_NONE = 0x0000,

KEY_ID_0 = 0x0008,
KEY_ID_1 = 0x0010,
KEY_ID_2 = 0x0020,
KEY_ID_3 = 0x0040,
KEY_ID_4 = 0x0080,
KEY_ID_5 = 0x0100,

KEY_ID_Multi ,

}KeyID_Enum_t;

typedef enum {
KEY_STATE_INIT = 0x0000,
KEY_STATE_JITTER = 0x2000,
KEY_STATE_PRESSED = 0x4000,
KEY_STATE_INTERIM1 = 0x6000,
KEY_STATE_INTERIM2 = 0x8000,
KEY_STATE_UNRELEASED = 0xA000,

}KeyState_Enum_t;

typedef enum {
KEY_EVENT_NONE = 0x0000,
KEY_EVENT_SHORT = 0x0001,
KEY_EVENT_LONG = 0x0002,
KEY_EVENT_DOUBLESHORT = 0x0003,
KEY_EVENT_SHORTLONG = 0x0004,

}KeyEvent_Enum_t;

typedef struct {
KeyID_Enum_t KeyID;
KeyState_Enum_t KeyState;
KeyEvent_Enum_t KeyEvent;
u32 KeyJitterTime;
u32 KeyPressedTime;
u32 KeyReleasedTime;

}KeyAction_Struct_t;


/*
*********************************************************************************************************
* FUNCTION PROTOTYPES
*********************************************************************************************************
*/

void Key_Init (void);
KeyID_Enum_t Key_GetID (void);
u16 Key_GetValue (void);

void Key_SetEventTime ( u32 NewKeyTime_Jitter ,
u32 NewKeyTime_Interval ,
u32 NewKeyTime_Long ,
u32 NewKeyTime_Double ) ;

#endif





AD采集中经常要用到数字滤波,不同情况下又有不同的滤波需求,分享下10种经典的软件滤波程序

经验分享admin 发表了文章 • 1 个评论 • 1377 次浏览 • 2014-10-15 22:39 • 来自相关话题

1、限幅滤波法(又称程序判断滤波法)
2、中位值滤波法
3、算术平均滤波法
4、递推平均滤波法(又称滑动平均滤波法)
5、中位值平均滤波法(又称防脉冲干扰平均滤波法)
6、限幅平均滤波法
7、一阶滞后滤波法
8、加权递推平均滤波法
9、消抖滤波法
10、限幅消抖滤波法
一\限副滤波

A、方法:
根据经验判断,确定两次采样允许的最大偏差值(设为A)
每次检测到新值时判断:
如果本次值与上次值之差<=A,则本次值有效
如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值
B、优点:
能有效克服因偶然因素引起的脉冲干扰
C、缺点
无法抑制那种周期性的干扰
平滑度差

程序:


/* A值可根据实际情况调整
value为有效值,new_value为当前采样值
滤波程序返回有效的实际值 */

#define A 10
char value;
char filter()
{
char new_value;
new_value = get_ad();
if ( ( new_value - value > A ) || ( value - new_value > A ) )
return value;
else
return new_value;
}


二\中位值滤波法
A、方法:
连续采样N次(N取奇数),把N次采样值按大小排列 ,取中间值为本次有效值
B、优点:
能有效克服因偶然因素引起的波动干扰,对温度、液位的变化缓慢的被测参数有良好的滤波效果
C、缺点:
对流量、速度等快速变化的参数不宜
程序:


/* N值可根据实际情况调整
排序采用冒泡法*/
#define N 11
char filter()
{
char value_buf[N];
char count,i,j,temp;
for ( count=0;count<N;count++)
{
value_buf[count] = get_ad();
delay();
}
for (j=0;j<N-1;j++)
{
for (i=0;i<N-j-1;i++)
{
if ( value_buf[i]>value_buf[i+1] )
{
temp = value_buf[i];
value_buf[i] = value_buf[i+1];
value_buf[i+1] = temp;
}
}
}
return value_buf[(N-1)/2];
} 查看全部
1、限幅滤波法(又称程序判断滤波法)
2、中位值滤波法
3、算术平均滤波法
4、递推平均滤波法(又称滑动平均滤波法)
5、中位值平均滤波法(又称防脉冲干扰平均滤波法)
6、限幅平均滤波法
7、一阶滞后滤波法
8、加权递推平均滤波法
9、消抖滤波法
10、限幅消抖滤波法
一\限副滤波

A、方法:
根据经验判断,确定两次采样允许的最大偏差值(设为A)
每次检测到新值时判断:
如果本次值与上次值之差<=A,则本次值有效
如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值
B、优点:
能有效克服因偶然因素引起的脉冲干扰
C、缺点
无法抑制那种周期性的干扰
平滑度差

程序:


/* A值可根据实际情况调整
value为有效值,new_value为当前采样值
滤波程序返回有效的实际值 */

#define A 10
char value;
char filter()
{
char new_value;
new_value = get_ad();
if ( ( new_value - value > A ) || ( value - new_value > A ) )
return value;
else
return new_value;
}


二\中位值滤波法
A、方法:
连续采样N次(N取奇数),把N次采样值按大小排列 ,取中间值为本次有效值
B、优点:
能有效克服因偶然因素引起的波动干扰,对温度、液位的变化缓慢的被测参数有良好的滤波效果
C、缺点:
对流量、速度等快速变化的参数不宜
程序:


/* N值可根据实际情况调整
排序采用冒泡法*/
#define N 11
char filter()
{
char value_buf[N];
char count,i,j,temp;
for ( count=0;count<N;count++)
{
value_buf[count] = get_ad();
delay();
}
for (j=0;j<N-1;j++)
{
for (i=0;i<N-j-1;i++)
{
if ( value_buf[i]>value_buf[i+1] )
{
temp = value_buf[i];
value_buf[i] = value_buf[i+1];
value_buf[i+1] = temp;
}
}
}
return value_buf[(N-1)/2];
}

高精度Pt100测温电路,RTD传感单元所需要的一种稳定的激励电流源及其应用电路,恒流接法

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

抛砖引玉!







介绍RTD传感单元所需要的一种稳定的激励电流源及其应用电路。如图所示,由一个电压参考源和两个运算放大器可以构成1mA的电流源。

按图中的条件,通过RREF的电流为IRTD=VREF/RREF。
该电路产生的电流与参考电压源的数值成正比,参考电源还可以作为模/数转换器的参考电源。
电路的绝对误差由下列因素决定:
参考电源的绝对误差
运算放大器的初始偏置电压
运算放大器A1的输出摆幅
电阻之间的匹配程度
RREF和RTD电阻的绝对值。温度的变化会引起上述元件的数值发生漂移,
由温度变化造成的基本误差来自:
电压参考源
运算放大器的偏置漂移


RTD元件的数值
RTD元件阻值的变化通常由A/D转换器量化,如图所示。RTD元件上的电压降由A3测出并通过A4构成的滤波器放大。在本电路中,要求选择三端RTD器件,这样的设置可以使引线电阻引起的误差最小,并使引线电阻随温度的漂移最小。
在本电路中,0℃时RTD元件的电阻为100佟H绻饬℃到300℃范围的温度变化,则RTD元件的电阻应在23俚僦洹S捎谙喽远裕缱杞系停叩缱韬鸵叩缱杷嫖露鹊钠苹岫晕露炔饬坎匾跋臁4游南譇N687中可以看到,当满足图2条件,且引线电阻相等时,运算放大器A3的输出电压等于RTD器件的输出电压。A3输出经过A4、R3、C3、R4和C4组成的滤波电路,才输入到A/D转换器。
从上述电路可见,采用RTD器件测量温度比采用热敏电阻或硅温度传感器所需要的外围调理电路更多,但是在较宽的温度范围内,其线性度和精度都较高。如果在微处理器内部进一步线性化,则RTD电路的测温精度可以达到±0.01℃。
 
下面再转一个pt100的测温电路
PT100是一种正温度系数的热敏电阻。说到什么是正温度系数?就必须要结合负温度系数来讲了。随着温度的升高,电阻的阻值变大,就是正温度系数的热敏电阻,相反,如果随着温度的升高,电阻的阻值变小,就是负温度系数的热敏电阻。


PT100之所以应用很广泛,不仅是因为它可以测的温度范围宽(零下几十度到零上几百度),还因为它的线性度非常好。“线性度”,说的直白一点就是温度每变化一度,电阻的阻值升高的幅度是基本相同的。这样,就大大的简化了我们的程序。

不过,PT100也有它的缺点,就是温度每上升一度,阻值变化太小了,只有0.39欧姆。这样就需要硬件上提供高精度低噪声的转换。

网上流传有很多电路,很多电路其实都是不能当作产品用的。下面给大家提供一种高精度的电路,就是成本有些高,不过品质好。





对于测温电路,其实有很多可以值得研究的地方,小电路有大智慧。比如,你可以一眼就看出来这个电路不能测零下的温度吗?你可以计算出来这个电路可以测量的温度范围是从多少度到多少度吗?你可以修改这个电路,让它可以测到你所需要的温度范围吗?如果把反相(-IN)和同相(+IN)两条线调换,后果如何?

看看,你觉得电路简单,那么上面的问题都可以回答吗?

电路解释:

越简单的电路,稳定性就越好。该电路中的四个电阻都需要用0.1%精度的。电路只用了一个电桥和一个差分放大器。R2 R3 R4与PT100组成电桥电路,REF3030为电桥电路提供标准的3.00V电压。AD623用一个2K的放大反馈电阻精确的把电桥的压差放大51倍。(为什么是51倍,详见AD623的datasheet)

PT100接法:

细心的小伙伴,会研究一下PT100的接法。PT100一般有两线和三线的传感器。因为线本身肯定有电阻,而上面也提到过,每变化一度,PT100只变化0.39欧姆,那么如果PT100的线很长的话,电阻就越大,线不同,电阻就不同,就肯定会大大的影响测出来的结果。所以,你现在就可以理解了,两线制的PT100,只适合短距离的应用。长距离的应用,就要用三线制。再让我们看看三线制是如何把电线上的电阻影响排除的。算了,还是下篇再讲吧,这个要画几个图才讲的清楚,时间不早了,懒得画了。

测温范围:

假设现在是0度,那么PT100的阻值就是100欧姆,在电路中的话,电桥的压差就是0V,所以最后也是0V,也就是测到0V的话,就是0度。假设现在零下一度了,PT100的阻值就小于100欧了,同相的电压就会比反相的电压小,得到的电压永远就0V了,所以这个电路就测不到0度以下。

AD623最大输出3.3V电压,3300/51=64.7mV,也就是说,电桥的压差,最大只能是64.7mV,再大的压差,AD623的输出也最大是3.3V了。反相臂的电压,固定是(3000/2100)*100=142.86mV,那么同相臂的电压最大只能是142.86+64.7=207.56mV,对应PT100的电阻就等于207.56/((3000-207.56)/2000)=148.66欧姆。
 





然后再查表,就可以看出,最大测温点差不多就是个127度。所以这个电路的测温范围就是0~127度。

关于如何修改电路测零下或者其他的温度范围,这里就不说了。大家可以自己研究。 查看全部
抛砖引玉!


ourdev_478700.gif


介绍RTD传感单元所需要的一种稳定的激励电流源及其应用电路。如图所示,由一个电压参考源和两个运算放大器可以构成1mA的电流源。

按图中的条件,通过RREF的电流为IRTD=VREF/RREF。
该电路产生的电流与参考电压源的数值成正比,参考电源还可以作为模/数转换器的参考电源。
电路的绝对误差由下列因素决定:
参考电源的绝对误差
运算放大器的初始偏置电压
运算放大器A1的输出摆幅
电阻之间的匹配程度
RREF和RTD电阻的绝对值。温度的变化会引起上述元件的数值发生漂移,
由温度变化造成的基本误差来自:
电压参考源
运算放大器的偏置漂移


RTD元件的数值
RTD元件阻值的变化通常由A/D转换器量化,如图所示。RTD元件上的电压降由A3测出并通过A4构成的滤波器放大。在本电路中,要求选择三端RTD器件,这样的设置可以使引线电阻引起的误差最小,并使引线电阻随温度的漂移最小。
在本电路中,0℃时RTD元件的电阻为100佟H绻饬℃到300℃范围的温度变化,则RTD元件的电阻应在23俚僦洹S捎谙喽远裕缱杞系停叩缱韬鸵叩缱杷嫖露鹊钠苹岫晕露炔饬坎匾跋臁4游南譇N687中可以看到,当满足图2条件,且引线电阻相等时,运算放大器A3的输出电压等于RTD器件的输出电压。A3输出经过A4、R3、C3、R4和C4组成的滤波电路,才输入到A/D转换器。
从上述电路可见,采用RTD器件测量温度比采用热敏电阻或硅温度传感器所需要的外围调理电路更多,但是在较宽的温度范围内,其线性度和精度都较高。如果在微处理器内部进一步线性化,则RTD电路的测温精度可以达到±0.01℃。
 
下面再转一个pt100的测温电路
PT100是一种正温度系数的热敏电阻。说到什么是正温度系数?就必须要结合负温度系数来讲了。随着温度的升高,电阻的阻值变大,就是正温度系数的热敏电阻,相反,如果随着温度的升高,电阻的阻值变小,就是负温度系数的热敏电阻。


PT100之所以应用很广泛,不仅是因为它可以测的温度范围宽(零下几十度到零上几百度),还因为它的线性度非常好。“线性度”,说的直白一点就是温度每变化一度,电阻的阻值升高的幅度是基本相同的。这样,就大大的简化了我们的程序。

不过,PT100也有它的缺点,就是温度每上升一度,阻值变化太小了,只有0.39欧姆。这样就需要硬件上提供高精度低噪声的转换。

网上流传有很多电路,很多电路其实都是不能当作产品用的。下面给大家提供一种高精度的电路,就是成本有些高,不过品质好。

615923327322.jpg

对于测温电路,其实有很多可以值得研究的地方,小电路有大智慧。比如,你可以一眼就看出来这个电路不能测零下的温度吗?你可以计算出来这个电路可以测量的温度范围是从多少度到多少度吗?你可以修改这个电路,让它可以测到你所需要的温度范围吗?如果把反相(-IN)和同相(+IN)两条线调换,后果如何?

看看,你觉得电路简单,那么上面的问题都可以回答吗?

电路解释:

越简单的电路,稳定性就越好。该电路中的四个电阻都需要用0.1%精度的。电路只用了一个电桥和一个差分放大器。R2 R3 R4与PT100组成电桥电路,REF3030为电桥电路提供标准的3.00V电压。AD623用一个2K的放大反馈电阻精确的把电桥的压差放大51倍。(为什么是51倍,详见AD623的datasheet)

PT100接法:

细心的小伙伴,会研究一下PT100的接法。PT100一般有两线和三线的传感器。因为线本身肯定有电阻,而上面也提到过,每变化一度,PT100只变化0.39欧姆,那么如果PT100的线很长的话,电阻就越大,线不同,电阻就不同,就肯定会大大的影响测出来的结果。所以,你现在就可以理解了,两线制的PT100,只适合短距离的应用。长距离的应用,就要用三线制。再让我们看看三线制是如何把电线上的电阻影响排除的。算了,还是下篇再讲吧,这个要画几个图才讲的清楚,时间不早了,懒得画了。

测温范围:

假设现在是0度,那么PT100的阻值就是100欧姆,在电路中的话,电桥的压差就是0V,所以最后也是0V,也就是测到0V的话,就是0度。假设现在零下一度了,PT100的阻值就小于100欧了,同相的电压就会比反相的电压小,得到的电压永远就0V了,所以这个电路就测不到0度以下。

AD623最大输出3.3V电压,3300/51=64.7mV,也就是说,电桥的压差,最大只能是64.7mV,再大的压差,AD623的输出也最大是3.3V了。反相臂的电压,固定是(3000/2100)*100=142.86mV,那么同相臂的电压最大只能是142.86+64.7=207.56mV,对应PT100的电阻就等于207.56/((3000-207.56)/2000)=148.66欧姆。
 

615923372358.jpg

然后再查表,就可以看出,最大测温点差不多就是个127度。所以这个电路的测温范围就是0~127度。

关于如何修改电路测零下或者其他的温度范围,这里就不说了。大家可以自己研究。

谈谈关于红外遥控接收程序的疑问?看到都在用中断处理,延时等待检测,没有效率可言

回复

问题困惑admin 发起了问题 • 2 人关注 • 0 个回复 • 1670 次浏览 • 2014-10-14 00:24 • 来自相关话题

stm32cube中文教程:按键检测怎么设置,举例说明如下

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

按键检测,就是按键作为输入,一般51的做法是IO口接上拉按键控制接地.
至于stm32cube中不需接上拉电阻,内置上啦就成了.
端口设置为GPIO_Input,上拉模式.
记得不是GPIO_OUTPUT模式啊,那个可不行
至于定时器设置为10ms定时就可以了,有人说设置为20ms最好,自己看了
我用定时器3,设置定时时间10ms
定时完成回调函数里面就定义一个标志,表示定时时间到
主程序中处理按键检测
我这里演示了3个按键的检测,用灯指示输出
随便写了个程序.


#include "stm32f4xx_hal.h"
#include "tim.h"
#include "gpio.h"

/[i] Private variables ---------------------------------------------------------[/i]/

/[i] USER CODE BEGIN 0 [/i]/
uint8_t update_flag = 0;
uint8_t key[2],c_time,key_v,key_s=0x07;
uint8_t get_value(void);
void key_scan(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(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]/
// uint8_t ReadData,Trg,Cont;
// uint8_t value;
// uint8_t value_pre = 0x07;
uint8_t key_flag;

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

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
// if(update_flag)
// {c_time++ ;update_flag=0;}
// if(c_time >=100) {HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 );c_time= 0;}
//

if(update_flag)
{
key_scan ();
update_flag = 0;
}
if(key_v != key_s)
{ key_s = key_v; key_flag = 1; }
if(key_flag)
{
key_flag = 0;
// HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 );
switch(key_s)
{
case 0x00 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_11 ); HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_12 );break;
case 0x01 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_12 ); break;
case 0x03 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_11 ); break;
case 0x07 : HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 ); break;
default : break;
}
}
}
/[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 = 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] USER CODE BEGIN 4 [/i]/
void key_scan(void)
{
key[ c_time ] = get_value ();
c_time ++;
if(c_time <= 1) return ;
c_time = 0;
if(key[1]==key[0]) key_v = key[0];
}
uint8_t get_value(void)
{
uint8_t PIN_value;
PIN_value = (HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_13)<<2) + (HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_14)<<1) + HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_15);
// PIN_value = HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_13);
return PIN_value;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
update_flag = 1;

}
/[i] USER CODE END 4 [/i]/ 查看全部
按键检测,就是按键作为输入,一般51的做法是IO口接上拉按键控制接地.
至于stm32cube中不需接上拉电阻,内置上啦就成了.
端口设置为GPIO_Input,上拉模式.
记得不是GPIO_OUTPUT模式啊,那个可不行
至于定时器设置为10ms定时就可以了,有人说设置为20ms最好,自己看了
我用定时器3,设置定时时间10ms
定时完成回调函数里面就定义一个标志,表示定时时间到
主程序中处理按键检测
我这里演示了3个按键的检测,用灯指示输出
随便写了个程序.


#include "stm32f4xx_hal.h"
#include "tim.h"
#include "gpio.h"

/[i] Private variables ---------------------------------------------------------[/i]/

/[i] USER CODE BEGIN 0 [/i]/
uint8_t update_flag = 0;
uint8_t key[2],c_time,key_v,key_s=0x07;
uint8_t get_value(void);
void key_scan(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(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]/
// uint8_t ReadData,Trg,Cont;
// uint8_t value;
// uint8_t value_pre = 0x07;
uint8_t key_flag;

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

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
// if(update_flag)
// {c_time++ ;update_flag=0;}
// if(c_time >=100) {HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 );c_time= 0;}
//

if(update_flag)
{
key_scan ();
update_flag = 0;
}
if(key_v != key_s)
{ key_s = key_v; key_flag = 1; }
if(key_flag)
{
key_flag = 0;
// HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 );
switch(key_s)
{
case 0x00 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_11 ); HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_12 );break;
case 0x01 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_12 ); break;
case 0x03 : HAL_GPIO_TogglePin( GPIOB, GPIO_PIN_11 ); break;
case 0x07 : HAL_GPIO_TogglePin( GPIOF, GPIO_PIN_6 ); break;
default : break;
}
}
}
/[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 = 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] USER CODE BEGIN 4 [/i]/
void key_scan(void)
{
key[ c_time ] = get_value ();
c_time ++;
if(c_time <= 1) return ;
c_time = 0;
if(key[1]==key[0]) key_v = key[0];
}
uint8_t get_value(void)
{
uint8_t PIN_value;
PIN_value = (HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_13)<<2) + (HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_14)<<1) + HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_15);
// PIN_value = HAL_GPIO_ReadPin (GPIOB,GPIO_PIN_13);
return PIN_value;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
update_flag = 1;

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

C语言中的问号语句没有if语句效率高

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

C语言里有一个三目运算符“?”,俗称“问号表达式”。很多程序员都很喜欢使用,因为它逻辑清晰表达简洁。

看这个问号表达式:c=(a>b) ? a+1 : b+1;实际上等效于以下的if…else结构:

if (a>b) c=a+1;

else c=b+1;

可以看到,使用问号表达式,语句相当简洁,但它的执行效率却很低,远没有if…else语句效率高。所以,当您的程序要求提高执行速度的话,建议您不要使用问号表达式了。

另外,do…while语句也比while语句的效率高。

代码的效率问题,不是我们编程中的主要问题,除了程序要求较高的执行速度或者单片机的ROM和RAM不够用的时候才会考虑。一般情况下,我们不用在乎。如果您一味追求高效率的代码,可能会影响代码的可读性和可维护性。 查看全部
C语言里有一个三目运算符“?”,俗称“问号表达式”。很多程序员都很喜欢使用,因为它逻辑清晰表达简洁。

看这个问号表达式:c=(a>b) ? a+1 : b+1;实际上等效于以下的if…else结构:

if (a>b) c=a+1;

else c=b+1;

可以看到,使用问号表达式,语句相当简洁,但它的执行效率却很低,远没有if…else语句效率高。所以,当您的程序要求提高执行速度的话,建议您不要使用问号表达式了。

另外,do…while语句也比while语句的效率高。

代码的效率问题,不是我们编程中的主要问题,除了程序要求较高的执行速度或者单片机的ROM和RAM不够用的时候才会考虑。一般情况下,我们不用在乎。如果您一味追求高效率的代码,可能会影响代码的可读性和可维护性。

stm32定时器深入研究:在定时中途修改此定时器的定时时间,会立即更改定时时间还是等待这次定时结束才更改?

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

今天遇到这样的问题?

就是比如定时器tim1初始化的定时时间是6s,表现为一个LED反转。
那么,如果我在定时途中修改这个定时器的定时时间参数,定时器是即时反应还是定时结束后统一更新?

比如现在定时为6s,然而我在定时途中2.5s的时候修改定时时间为2s,那么是在第4.5s就立马定时中断,还是继续上次的6s定时后进行呢?

于是我做了实验。

就是上面我提到的定时参数一样。

结果是:程序在2.5s更改参数后,立即以2s的定时开始运行,也就是紧接着执行了定时2s的中断,于是我得出,定时器修改参数后会立即转到新的参数进行运行!

希望大家共勉!实验才是硬道理啊。哈哈
好吧,2楼实验程序也贴出来,程序用的stm32cubemx自动生成。 查看全部
今天遇到这样的问题?

就是比如定时器tim1初始化的定时时间是6s,表现为一个LED反转。
那么,如果我在定时途中修改这个定时器的定时时间参数,定时器是即时反应还是定时结束后统一更新?

比如现在定时为6s,然而我在定时途中2.5s的时候修改定时时间为2s,那么是在第4.5s就立马定时中断,还是继续上次的6s定时后进行呢?

于是我做了实验。

就是上面我提到的定时参数一样。

结果是:程序在2.5s更改参数后,立即以2s的定时开始运行,也就是紧接着执行了定时2s的中断,于是我得出,定时器修改参数后会立即转到新的参数进行运行!

希望大家共勉!实验才是硬道理啊。哈哈
好吧,2楼实验程序也贴出来,程序用的stm32cubemx自动生成。

关于HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)的研究

问题困惑admin 发表了文章 • 10 个评论 • 8433 次浏览 • 2014-10-14 00:19 • 来自相关话题

HAL_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size)
从它的函数内容考看,其实就是初始化了下uart端口,定义了下接收到的数据的缓存器名,还有定义了接收尺寸,然后开启了UART_IT_RXNE,即接收非空中断,然后静等中断发生。
2楼继续。

中断发生后。
进入
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
// cont_uart++;
}
先清除等待标志,后进入中断处理
进入
tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
/ UART in mode Receiver ---------------------------------------------------/
if((tmp1 != RESET) && (tmp2 != RESET))
{
UART_Receive_IT(huart);
}
判断接收到非空数据,并且RXEN中断开启了,则执行数据接收UART_Receive_IT(huart);
8位,none,所以执行
if(huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
得到数据,存到pRxBuffPtr的指向地址缓存器里
3楼继续

接上面
if(--huart->RxXferCount == 0)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

/ Check if a transmit process is ongoing or not /
if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
{
huart->State = HAL_UART_STATE_BUSY_TX;
}
else
{
/ Disable the UART Parity Error Interrupt /
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);

/ Disable the UART Error Interrupt: (Frame error, noise error, overrun error) /
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

huart->State = HAL_UART_STATE_READY;
}
HAL_UART_RxCpltCallback(huart);

return HAL_OK;
}
计数自减1,判断是否是0,不是0则说明还么接收完
则程序返回,再次接收到一个字节,产生中断再次执行。
直到--huart->RxXferCount == 0
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); 关闭RXEN接收非空中断
再判断是否在传送,没有则关闭UART Parity Error Interrupt
关闭UART Error Interrupt: (Frame error, noise error, overrun error)
并且 调用接收完成回调函数,HAL_UART_RxCpltCallback(huart);
继续接4楼

接楼上
说明每次接收完数据,只要没发送状态
uart的接收中断全部关闭了,要想连续的接收数据,则需要在
HAL_UART_RxCpltCallback(huart);函数中开启RXEN中断

/ Enable the UART Parity Error Interrupt /
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);

/ Enable the UART Error Interrupt: (Frame error, noise error, overrun error) /
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

/ Process Unlocked /
__HAL_UNLOCK(huart);

/ Enable the UART Data Register not empty Interrupt /
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

即需要再次调用HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);函数,。
下面测试:
在main中添加
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);

}
测试失败,第一次能接收到,第二次数据接收不到。
将 HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);写入到
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);
cont_uart++;
}
测试成功,可以接收到8位数据。
不过,如果数据超过8位,则超过部分会覆盖掉以前的数据
如:8位数据是,1、2、3、4、5、6、7、8
发送的10位数据:则接收到的会把前两位覆盖,最终接收的数据是
10、9、3、4、5、6、7、8
测试代码是接收8位,要改成10位同样道理,反正超过了接收的就是不对的数据

分析上面的
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);
cont_uart++;
}
接收到小于设定的长度值无所谓,能正常获取
大于之后覆盖
因为接收完8个数据,清除中断,然后Hal_ready = ok,等到第九个数据过来产生中断 查看全部
HAL_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size)
从它的函数内容考看,其实就是初始化了下uart端口,定义了下接收到的数据的缓存器名,还有定义了接收尺寸,然后开启了UART_IT_RXNE,即接收非空中断,然后静等中断发生。
2楼继续。

中断发生后。
进入
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
// cont_uart++;
}
先清除等待标志,后进入中断处理
进入
tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
/ UART in mode Receiver ---------------------------------------------------/
if((tmp1 != RESET) && (tmp2 != RESET))
{
UART_Receive_IT(huart);
}
判断接收到非空数据,并且RXEN中断开启了,则执行数据接收UART_Receive_IT(huart);
8位,none,所以执行
if(huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
得到数据,存到pRxBuffPtr的指向地址缓存器里
3楼继续

接上面
if(--huart->RxXferCount == 0)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

/ Check if a transmit process is ongoing or not /
if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
{
huart->State = HAL_UART_STATE_BUSY_TX;
}
else
{
/ Disable the UART Parity Error Interrupt /
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);

/ Disable the UART Error Interrupt: (Frame error, noise error, overrun error) /
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

huart->State = HAL_UART_STATE_READY;
}
HAL_UART_RxCpltCallback(huart);

return HAL_OK;
}
计数自减1,判断是否是0,不是0则说明还么接收完
则程序返回,再次接收到一个字节,产生中断再次执行。
直到--huart->RxXferCount == 0
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); 关闭RXEN接收非空中断
再判断是否在传送,没有则关闭UART Parity Error Interrupt
关闭UART Error Interrupt: (Frame error, noise error, overrun error)
并且 调用接收完成回调函数,HAL_UART_RxCpltCallback(huart);
继续接4楼

接楼上
说明每次接收完数据,只要没发送状态
uart的接收中断全部关闭了,要想连续的接收数据,则需要在
HAL_UART_RxCpltCallback(huart);函数中开启RXEN中断

/ Enable the UART Parity Error Interrupt /
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);

/ Enable the UART Error Interrupt: (Frame error, noise error, overrun error) /
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

/ Process Unlocked /
__HAL_UNLOCK(huart);

/ Enable the UART Data Register not empty Interrupt /
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

即需要再次调用HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);函数,。
下面测试:
在main中添加
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);

}
测试失败,第一次能接收到,第二次数据接收不到。
将 HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);写入到
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);
cont_uart++;
}
测试成功,可以接收到8位数据。
不过,如果数据超过8位,则超过部分会覆盖掉以前的数据
如:8位数据是,1、2、3、4、5、6、7、8
发送的10位数据:则接收到的会把前两位覆盖,最终接收的数据是
10、9、3、4、5、6、7、8
测试代码是接收8位,要改成10位同样道理,反正超过了接收的就是不对的数据

分析上面的
void USART1_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
HAL_UART_IRQHandler(&huart1);
HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8);
cont_uart++;
}
接收到小于设定的长度值无所谓,能正常获取
大于之后覆盖
因为接收完8个数据,清除中断,然后Hal_ready = ok,等到第九个数据过来产生中断