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

问题困惑admin 发表了文章 • 10 个评论 • 6856 次浏览 • 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,等到第九个数据过来产生中断

stm32cube中文教程:TIM3定时,TIM1双通道计数器的实现

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

本次利用了,stm32cubemx生成代码,稍微在main中添加得到
打开cubemx,先设置pinout选项卡。
rcc选择crystal。外部时钟
TIM1中选择Channel1的Input Capture direct mode
TIM1中选择Channel2的Input Capture direct mode

TIM3中Clock Source选择Internal Clock
Usart1中MOde选择Asynchronous

其他所有的默认即可。
TIM1用于计数,两个通道同时计数。
TIM3用于定时,并且生成一个脉冲信号
usart用于输出计数结果

Clock configuration选项卡中
时钟我用的25M晶振,系统时钟设为168MHz
APB1 Prescaler 选4,APB2 Prescaler选2

Configuration选项卡中,
usart设置不再讲述,可以去看网站里面的帖子
NVIC按钮打开后,TIM1 Capture Compare interrupt 设为0,2
TIM3 gloable interrupt 设置 0,1
并且以上开启使能
TIM1设置页打开后 counter period (autoreload register-16bits value) 设为65535,up,其他不变,tim1的gpio都设为Pull-up,high
Tim3设置页 prescaler (psc-16 bits value) 为8399
紧接着up,继续9999
最后update event。

好了,设置结束,生成代码,
main.c中的代码:其他的文件没变啊,自己对比添加了哪些吧,懒得一个个写


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

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

UART_HandleTypeDef huart1;

/[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(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
uint32_t cont_value1 = 0;
uint32_t cont_value2 = 0;
uint32_t v_value1 = 0;
uint32_t v_value2 = 0;
static void Error_Handler(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_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] 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_TIM1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
/[i] USER CODE END 2 [/i]/

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

// printf ("hello ,my world!");
HAL_Delay(1000);
printf ("%d , %d \r\n",v_value1, v_value2);
cont_value1= 0;cont_value2= 0;

}
/[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] TIM1 init function [/i]/
void MX_TIM1_Init(void)
{

TIM_IC_InitTypeDef sConfigIC;
TIM_MasterConfigTypeDef sMasterConfig;

htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_IC_Init(&htim1);

sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);

HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

}

/[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 = 99;
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);

}

/[i] USART1 init function [/i]/
void MX_USART1_UART_Init(void)
{

huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);

}

/** 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();
__GPIOE_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]/
static void Error_Handler(void)
{
/[i] Turn LED3 on [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1)
{
}
}
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
*/
v_value1 = cont_value1;v_value2 = cont_value2;
// cont_value = 0;
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/**
* @brief Conversion complete callback in non blocking mode
* @param htim : hadc handle
* @retval None
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value1 ++;

}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value2 ++;

}
}
/[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)
{
/[i] USER CODE BEGIN 6 [/i]/
/* 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) */
/[i] USER CODE END 6 [/i]/

}

#endif 查看全部
本次利用了,stm32cubemx生成代码,稍微在main中添加得到
打开cubemx,先设置pinout选项卡。
rcc选择crystal。外部时钟
TIM1中选择Channel1的Input Capture direct mode
TIM1中选择Channel2的Input Capture direct mode

TIM3中Clock Source选择Internal Clock
Usart1中MOde选择Asynchronous

其他所有的默认即可。
TIM1用于计数,两个通道同时计数。
TIM3用于定时,并且生成一个脉冲信号
usart用于输出计数结果

Clock configuration选项卡中
时钟我用的25M晶振,系统时钟设为168MHz
APB1 Prescaler 选4,APB2 Prescaler选2

Configuration选项卡中,
usart设置不再讲述,可以去看网站里面的帖子
NVIC按钮打开后,TIM1 Capture Compare interrupt 设为0,2
TIM3 gloable interrupt 设置 0,1
并且以上开启使能
TIM1设置页打开后 counter period (autoreload register-16bits value) 设为65535,up,其他不变,tim1的gpio都设为Pull-up,high
Tim3设置页 prescaler (psc-16 bits value) 为8399
紧接着up,继续9999
最后update event。

好了,设置结束,生成代码,
main.c中的代码:其他的文件没变啊,自己对比添加了哪些吧,懒得一个个写


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

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

UART_HandleTypeDef huart1;

/[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(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
uint32_t cont_value1 = 0;
uint32_t cont_value2 = 0;
uint32_t v_value1 = 0;
uint32_t v_value2 = 0;
static void Error_Handler(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_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] 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_TIM1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
/[i] USER CODE END 2 [/i]/

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

// printf ("hello ,my world!");
HAL_Delay(1000);
printf ("%d , %d \r\n",v_value1, v_value2);
cont_value1= 0;cont_value2= 0;

}
/[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] TIM1 init function [/i]/
void MX_TIM1_Init(void)
{

TIM_IC_InitTypeDef sConfigIC;
TIM_MasterConfigTypeDef sMasterConfig;

htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_IC_Init(&htim1);

sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);

HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

}

/[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 = 99;
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);

}

/[i] USART1 init function [/i]/
void MX_USART1_UART_Init(void)
{

huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);

}

/** 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();
__GPIOE_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]/
static void Error_Handler(void)
{
/[i] Turn LED3 on [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1)
{
}
}
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
*/
v_value1 = cont_value1;v_value2 = cont_value2;
// cont_value = 0;
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/**
* @brief Conversion complete callback in non blocking mode
* @param htim : hadc handle
* @retval None
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value1 ++;

}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value2 ++;

}
}
/[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)
{
/[i] USER CODE BEGIN 6 [/i]/
/* 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) */
/[i] USER CODE END 6 [/i]/

}

#endif

stm32cube中文教程:运行中修改TIM定时时间的例子将1s定时运行中改成200ms定时

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

本实验用stm32cubemx生成定时器4的1s定时,然后准备在运行过程中更改定时时间
考虑程序中初始化后定时修改时再次init初始化,应该就可以了。
关于用stm32cube生成定时的方法,请找本论坛文章。
本程序只在原来定时中断中增加了再次初始化代码。
运行正常,测试通过。
代码如下:

其他代码不给出了,只贴出修改了的代码:
在main文件中的定时中断函数中增加:


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
*/
flag++;
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_14);
if(flag==20)
{
htim4.Init.Period = 1999;
HAL_TIM_Base_Init(&htim4);
}
}

其中flag是计数标示,用来记进入了几次中断,程序中断20次后,修改Period ,然后固化,
之后程序开始以200ms开始闪烁。灯是PD14. 查看全部
本实验用stm32cubemx生成定时器4的1s定时,然后准备在运行过程中更改定时时间
考虑程序中初始化后定时修改时再次init初始化,应该就可以了。
关于用stm32cube生成定时的方法,请找本论坛文章。
本程序只在原来定时中断中增加了再次初始化代码。
运行正常,测试通过。
代码如下:

其他代码不给出了,只贴出修改了的代码:
在main文件中的定时中断函数中增加:


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
*/
flag++;
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_14);
if(flag==20)
{
htim4.Init.Period = 1999;
HAL_TIM_Base_Init(&htim4);
}
}

其中flag是计数标示,用来记进入了几次中断,程序中断20次后,修改Period ,然后固化,
之后程序开始以200ms开始闪烁。灯是PD14.

stm32cube中文教程:DAC输出模拟电压,用12位精度DA最大3.3v,学习笔记

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

用stm32cubemx生成DA输出真对stm32f407的模拟输出电压,很简单
首先,配置时钟,168M,我用的stm32f407discovery板。
这些配置操作我以前提到过,不懂的可以在这个论坛里找找,有图文注释的。
直接点取DAC的通道1,然后去configariton里面配置DAC,其实无需配置,不用改任何东西
生成代码。
打开main文件,找到main函数中初始化后添加:
这个是我自己的例子,你可以适当修改


/[i][size=16]-4- Enable DAC Channel1 [/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_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
{
/[i] Start Error [/i]/
Error_Handler();
}

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

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


HAL_Delay (1);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value );
if(!flag)
{ value ++; if(value==0xfff){ flag=1; }} else { value--;if(!value) flag=0; }
}

代码注释:第一个意思是开启dac的通道1.
while中的意思是:设置DA的值,我用的12位精度,右对齐,值是value,通道DAC_CHANNEL_1
值value从0增加到4095即0xfff,然后从0xfff减小到0,无限循环,哦,上面还有个指示灯,不过
这么高的频率是指示不出来的。是i我调试其他的时候加的,可以无视它。

用示波器 测量PA4管脚(这个就是DA的输出口1),会看到波形类似三角波,电压是从0升到3.3然后再降到0v,ok,结束实验 查看全部
用stm32cubemx生成DA输出真对stm32f407的模拟输出电压,很简单
首先,配置时钟,168M,我用的stm32f407discovery板。
这些配置操作我以前提到过,不懂的可以在这个论坛里找找,有图文注释的。
直接点取DAC的通道1,然后去configariton里面配置DAC,其实无需配置,不用改任何东西
生成代码。
打开main文件,找到main函数中初始化后添加:
这个是我自己的例子,你可以适当修改


/[i][size=16]-4- Enable DAC Channel1 [/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_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
{
/[i] Start Error [/i]/
Error_Handler();
}

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

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


HAL_Delay (1);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value );
if(!flag)
{ value ++; if(value==0xfff){ flag=1; }} else { value--;if(!value) flag=0; }
}

代码注释:第一个意思是开启dac的通道1.
while中的意思是:设置DA的值,我用的12位精度,右对齐,值是value,通道DAC_CHANNEL_1
值value从0增加到4095即0xfff,然后从0xfff减小到0,无限循环,哦,上面还有个指示灯,不过
这么高的频率是指示不出来的。是i我调试其他的时候加的,可以无视它。

用示波器 测量PA4管脚(这个就是DA的输出口1),会看到波形类似三角波,电压是从0升到3.3然后再降到0v,ok,结束实验

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

软件教程admin 发表了文章 • 27 个评论 • 4214 次浏览 • 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 个评论 • 2515 次浏览 • 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 个评论 • 7896 次浏览 • 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 个评论 • 1401 次浏览 • 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 个评论 • 2008 次浏览 • 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 个回复 • 1725 次浏览 • 2014-10-13 23:52 • 来自相关话题

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

经验分享admin 发表了文章 • 1 个评论 • 1495 次浏览 • 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 个评论 • 3723 次浏览 • 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 个评论 • 1329 次浏览 • 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 个评论 • 1219 次浏览 • 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 个评论 • 3294 次浏览 • 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 /