注意:demo.c 不要加入到程序中来。
1 在main.h文件中加入 #include "stm32f1xx_hal.h" 文件也可以不加
a: 每次重新生成程序时 在主程序main.c中注释掉// MX_USART2_UART_Init();函数,因为在freemodbus中已经调用了该 函数
b: 在uart.c中重写程序void MX_USART2_UART_Init(void)为
void MX_USART2_UART_Init (uint8_t ucPORT, uint32_t ulBaudRate, uint8_t eParity)
{
if(ucPORT != 2)
return ;
huart2.Instance = DEBUG_USART;
huart2.Init.BaudRate = ulBaudRate;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = eParity;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
while(1);
}
}
在uart.h中也要改写void MX_USART2_UART_Init (uint8_t ucPORT, uint32_t ulBaudRate, uint8_t eParity)
2 在main.c中加入#include "mb.h" #include "mbport.h" #include "user_mb_app.h" 三个文件
3 分别加入modbus驱动的c文件,定义h文件的路径
4 在main.c中加入:
define MB_SAMPLE_TEST_SLAVE_ADDR 1
extern UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
extern UCHAR ucSCoilBuf[S_COIL_NCOILS/8];
extern USHORT usSRegInBuf[S_REG_INPUT_NREGS];
extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
加入:eMBInit( MB_RTU, MB_SAMPLE_TEST_SLAVE_ADDR, MB_MASTER_USARTx, MB_MASTER_USART_BAUDRATE, MB_PAR_NONE);
加入:eMBEnable(); 和eMBPoll( );
在main.c开始加入modbus地址宏定义#define MB_SAMPLE_TEST_SLAVE_ADDR 1
5 在uart.h中加入
/* USER CODE BEGIN Includes */
//引脚定义
/usart******/
define DEBUG_USART USART2
define DEBUG_USART_CLK_ENABLE() __USART2_CLK_ENABLE();
define RCC_PERIPHCLK_UARTx RCC_PERIPHCLK_USART2
define RCC_UARTxCLKSOURCE_SYSCLK RCC_USART2CLKSOURCE_SYSCLK
define __HAL_RCC_USARTx_CLK_DISABLE __HAL_RCC_USART2_CLK_DISABLE();
define DEBUG_USART_RX_GPIO_PORT GPIOA
define DEBUG_USART_RX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE()
define DEBUG_USART_RX_PIN GPIO_PIN_3
define DEBUG_USART_TX_GPIO_PORT GPIOA
define DEBUG_USART_TX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE()
define DEBUG_USART_TX_PIN GPIO_PIN_2
define DEBUG_USART_IRQHandler USART2_IRQHandler
define DEBUG_USART_IRQ USART2_IRQn
define MB_MASTER_USARTx 2 //使用串口2
define MB_MASTER_USART_BAUDRATE 9600 //波特率
define MB_MASTER_USART_PARITY UART_PARITY_NONE
/usart end/
/485************************/
/* 如果需要使用串口转485 请打开此宏 */
//#define MODBUS_MASTER_USE_CONTROL_PIN
define MODBUS_MASTER_GPIO_PORT GPIOC
define MODBUS_MASTER_GPIO_PIN GPIO_PIN_2
define MODBUS_MASTER_GPIO_PIN_HIGH GPIO_PIN_SET
define MODBUS_MASTER_GPIO_PIN_LOW GPIO_PIN_RESET
define MODBUS_MASTER_GPIO_CLK_ENABLE() __GPIOC_CLK_ENABLE()
/***********************485 end*************************************/
加入以上文件
6 修改stm32f1xx_it.c文件增加以下三个文件
extern void prvvUARTTxReadyISR(void);
extern void prvvUARTRxISR(void);
extern void prvvTIMERExpiredISR( void );
7 在stm32f1xx_it.c文件中;函数void USART2_IRQHandler(void)中增加:(选择是发送中断还是接收中断)
if(__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE)!= RESET)
{
prvvUARTRxISR(); }
if(__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_TXE)!= RESET)
{
prvvUARTTxReadyISR(); }
HAL_NVIC_ClearPendingIRQ(USART2_IRQn);
HAL_UART_IRQHandler(&huart2);
8 在stm32f1xx_it.c文件中;增加一个函数:
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
*/
prvvTIMERExpiredISR( );
}
//以上是modbus在使用Hall库时的移置说明//
//以下是关于定时器的使用说明**********//
在主程序中加入 HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)此函数在stm32f1xx_hal_time.c中存在
以中断的方式启动定时器
在主程序主循环中加入:__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,pluse_wide );改变脉冲的宽度
在定时器tim3的中断函数void TIM3_IRQHandler(void)中加入 pluse_wide++;定时改变脉冲宽度
tim.c中htim4.Init.Prescaler = 3200;(初始化为20kHZ) 然后htim4.Init.Period = 35;(3.5时间溢出)
开发板与ttl转485的链接
ttl转485的RX端链接到开发板的A3(开发板的接收端) TX端接A2(开发板发送端)
A+接T/R+ B-接T/R-
#define PRO_CMD_LEN 5;
uint8_t rxBufPos=0;
uint8_t proBuffer[10]="#s456;\n";//定义要发送的数据
uint8_t rxBuffer[10]
uint8_t rxCompleted=RESET;
// 串口接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
rxCompleted=SET ;//中断接收完成
__HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE);//开启串口空闲中断
}
void on_UART_IDLE(UART_HandleTypeDef *huart)//检测idle中断事件并处理
{
if(__HAL_UART_GET_IT_SOURCE(huart,UART_IT_IDLE)==RESET)//判断IDLE中断是否开启
return;
__HAL_UART_CLEAR_IDLEFLAG(huart); //清除中断空闲标志位
__HAL_UART_DISABLE_IT(huart,UART_IT_IDLE); //禁止idle事件中断
if( rxCompleted) //已定义了rxcompleted为uint8_t已经接收了一个字节
{
unsigned char ch = rxBuffer[0];
if( rxBuffer[0]=="#") //如果是起始位
rxBufPos=0; //存储位置复位
if(rxBufPos<PRO_CMD_LEN ) //如果存储缓冲区小于设定长度
{
proBuffer[rxBufPos]=ch;
rxBufPos++;
if(ch==";") //如果接收到 ;
{
HAL_UART_Transmit(huart,proBuffer,sizeof (proBuffer),200);
HAL_Delay(100);
//加入其他的处理指令
}
}
rxCompleted=RESET;
HAL_UART_Receive_IT(huart,rxBuffer,PRO_CMD_LEN);//再次接收
//将RX_CMD_LEN设置为1,调用HAL_UART_Receive_IT(huart,rxBuffer,RX_CMD_LEN)
// 这样每接收一个字符会开启一次中断。在HAL_UART_RxCpltCallback()里开启IDLE事件中断
//就会执行 void on_UART_IDLE(UART_HandleTypeDef *huart)函数
}
}
使用定时器1输出PWM波说明
HAL_TIM_Base_Start(&htim1);//启动定时器
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启动PWM输出
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0X0037);//修改CCR值,即改变脉冲宽度
( htim3.Init.Prescaler = 1440; htim3.Init.Period = 10; sConfigOC.Pulse = 7; 频率为72000000/1440x10 有10个脉冲为1周期其中有7个脉冲为高电平 )
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1n);//定义互补通道要增加 #define TIM_CHANNEL_1n 0x00000002U 的宏定义 #define TIM_CHANNEL_1 0x00000000U
#define TIM_CHANNEL_1n 0x00000002U #define TIM_CHANNEL_2 0x00000004U
#define TIM_CHANNEL_2n 0x00000006U #define TIM_CHANNEL_3 0x00000008U
#define TIM_CHANNEL_3n 0x0000000AU #define TIM_CHANNEL_4 0x0000000CU
#define TIM_CHANNEL_4n 0x0000000EU #define TIM_CHANNEL_ALL 0x00000018U//定义互补通道
使用基础定时器TIM4进行定时说明
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);
在主程序中加入 HAL_TIM_Base_Start_IT(&htim4);//以中断方式启动定时器
或者加入以下4个宏函数:
vMBPortTimersEnable( )
{
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_SET_COUNTER(&htim4,0);
__HAL_TIM_ENABLE(&htim4); //使能定时器
}
vMBPortTimersDisable( )
{
/* 关闭定时器 */
__HAL_TIM_DISABLE(&htim4);
__HAL_TIM_SET_COUNTER(&htim4,0);
__HAL_TIM_DISABLE_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_UPDATE);
}
这个函数处理TIM3全局中断 void TIM3_IRQHandler(void)
在tim.c中加入
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);}
切换pc13的状态
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//在stm32fxx_hal_tim.c中是弱函数存在,必须重写
} 或者在 it.c中加入也可以
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
}//基础定时器只需要选择内部时针
关于串口数据传输
所有的串口ISR都是调用HAL_UART_IRQHandler();这个处理函数,这个函数是中断处理通用函数
这个函数会判断产生中断的事件的类型,清除事件中断的标志位,调用中断事件类型的中断回调函数
注意:demo.c 不要加入到程序中来。
1 在main.h文件中加入 #include "stm32f1xx_hal.h" 文件也可以不加
a: 每次重新生成程序时 在主程序main.c中注释掉// MX_USART2_UART_Init();函数,因为在freemodbus中已经调用了该 函数
b: 在uart.c中重写程序void MX_USART2_UART_Init(void)为
void MX_USART2_UART_Init (uint8_t ucPORT, uint32_t ulBaudRate, uint8_t eParity)
{
if(ucPORT != 2)
return ;
huart2.Instance = DEBUG_USART;
huart2.Init.BaudRate = ulBaudRate;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = eParity;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
while(1);
}
}
在uart.h中也要改写void MX_USART2_UART_Init (uint8_t ucPORT, uint32_t ulBaudRate, uint8_t eParity)
2 在main.c中加入#include "mb.h" #include "mbport.h" #include "user_mb_app.h" 三个文件
3 分别加入modbus驱动的c文件,定义h文件的路径
4 在main.c中加入:
define MB_SAMPLE_TEST_SLAVE_ADDR 1
extern UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
extern UCHAR ucSCoilBuf[S_COIL_NCOILS/8];
extern USHORT usSRegInBuf[S_REG_INPUT_NREGS];
extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
加入:eMBInit( MB_RTU, MB_SAMPLE_TEST_SLAVE_ADDR, MB_MASTER_USARTx, MB_MASTER_USART_BAUDRATE, MB_PAR_NONE);
加入:eMBEnable(); 和eMBPoll( );
在main.c开始加入modbus地址宏定义#define MB_SAMPLE_TEST_SLAVE_ADDR 1
5 在uart.h中加入
/* USER CODE BEGIN Includes */
//引脚定义
/usart******/
define DEBUG_USART USART2
define DEBUG_USART_CLK_ENABLE() __USART2_CLK_ENABLE();
define RCC_PERIPHCLK_UARTx RCC_PERIPHCLK_USART2
define RCC_UARTxCLKSOURCE_SYSCLK RCC_USART2CLKSOURCE_SYSCLK
define __HAL_RCC_USARTx_CLK_DISABLE __HAL_RCC_USART2_CLK_DISABLE();
define DEBUG_USART_RX_GPIO_PORT GPIOA
define DEBUG_USART_RX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE()
define DEBUG_USART_RX_PIN GPIO_PIN_3
define DEBUG_USART_TX_GPIO_PORT GPIOA
define DEBUG_USART_TX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE()
define DEBUG_USART_TX_PIN GPIO_PIN_2
define DEBUG_USART_IRQHandler USART2_IRQHandler
define DEBUG_USART_IRQ USART2_IRQn
define MB_MASTER_USARTx 2 //使用串口2
define MB_MASTER_USART_BAUDRATE 9600 //波特率
define MB_MASTER_USART_PARITY UART_PARITY_NONE
/usart end/
/485************************/
/* 如果需要使用串口转485 请打开此宏 */
//#define MODBUS_MASTER_USE_CONTROL_PIN
define MODBUS_MASTER_GPIO_PORT GPIOC
define MODBUS_MASTER_GPIO_PIN GPIO_PIN_2
define MODBUS_MASTER_GPIO_PIN_HIGH GPIO_PIN_SET
define MODBUS_MASTER_GPIO_PIN_LOW GPIO_PIN_RESET
define MODBUS_MASTER_GPIO_CLK_ENABLE() __GPIOC_CLK_ENABLE()
/***********************485 end*************************************/
加入以上文件
6 修改stm32f1xx_it.c文件增加以下三个文件
extern void prvvUARTTxReadyISR(void);
extern void prvvUARTRxISR(void);
extern void prvvTIMERExpiredISR( void );
7 在stm32f1xx_it.c文件中;函数void USART2_IRQHandler(void)中增加:(选择是发送中断还是接收中断)
if(__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE)!= RESET)
{
prvvUARTRxISR(); }
if(__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_TXE)!= RESET)
{
prvvUARTTxReadyISR(); }
HAL_NVIC_ClearPendingIRQ(USART2_IRQn);
HAL_UART_IRQHandler(&huart2);
8 在stm32f1xx_it.c文件中;增加一个函数:
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
*/
prvvTIMERExpiredISR( );
}
//以上是modbus在使用Hall库时的移置说明//
//以下是关于定时器的使用说明**********//
在主程序中加入 HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)此函数在stm32f1xx_hal_time.c中存在
以中断的方式启动定时器
在主程序主循环中加入:__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,pluse_wide );改变脉冲的宽度
在定时器tim3的中断函数void TIM3_IRQHandler(void)中加入 pluse_wide++;定时改变脉冲宽度
tim.c中htim4.Init.Prescaler = 3200;(初始化为20kHZ) 然后htim4.Init.Period = 35;(3.5时间溢出)
开发板与ttl转485的链接
ttl转485的RX端链接到开发板的A3(开发板的接收端) TX端接A2(开发板发送端)
A+接T/R+ B-接T/R-
#define PRO_CMD_LEN 5;
uint8_t rxBufPos=0;
uint8_t proBuffer[10]="#s456;\n";//定义要发送的数据
uint8_t rxBuffer[10]
uint8_t rxCompleted=RESET;
// 串口接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
rxCompleted=SET ;//中断接收完成
__HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE);//开启串口空闲中断
}
void on_UART_IDLE(UART_HandleTypeDef *huart)//检测idle中断事件并处理
{
if(__HAL_UART_GET_IT_SOURCE(huart,UART_IT_IDLE)==RESET)//判断IDLE中断是否开启
return;
__HAL_UART_CLEAR_IDLEFLAG(huart); //清除中断空闲标志位
__HAL_UART_DISABLE_IT(huart,UART_IT_IDLE); //禁止idle事件中断
if( rxCompleted) //已定义了rxcompleted为uint8_t已经接收了一个字节
{
unsigned char ch = rxBuffer[0];
if( rxBuffer[0]=="#") //如果是起始位
rxBufPos=0; //存储位置复位
if(rxBufPos<PRO_CMD_LEN ) //如果存储缓冲区小于设定长度
{
proBuffer[rxBufPos]=ch;
rxBufPos++;
if(ch==";") //如果接收到 ;
{
HAL_UART_Transmit(huart,proBuffer,sizeof (proBuffer),200);
HAL_Delay(100);
//加入其他的处理指令
}
}
rxCompleted=RESET;
HAL_UART_Receive_IT(huart,rxBuffer,PRO_CMD_LEN);//再次接收
//将RX_CMD_LEN设置为1,调用HAL_UART_Receive_IT(huart,rxBuffer,RX_CMD_LEN)
// 这样每接收一个字符会开启一次中断。在HAL_UART_RxCpltCallback()里开启IDLE事件中断
//就会执行 void on_UART_IDLE(UART_HandleTypeDef *huart)函数
}
}
使用定时器1输出PWM波说明
HAL_TIM_Base_Start(&htim1);//启动定时器
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启动PWM输出
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0X0037);//修改CCR值,即改变脉冲宽度
( htim3.Init.Prescaler = 1440; htim3.Init.Period = 10; sConfigOC.Pulse = 7; 频率为72000000/1440x10 有10个脉冲为1周期其中有7个脉冲为高电平 )
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1n);//定义互补通道要增加 #define TIM_CHANNEL_1n 0x00000002U 的宏定义 #define TIM_CHANNEL_1 0x00000000U
#define TIM_CHANNEL_1n 0x00000002U #define TIM_CHANNEL_2 0x00000004U
#define TIM_CHANNEL_2n 0x00000006U #define TIM_CHANNEL_3 0x00000008U
#define TIM_CHANNEL_3n 0x0000000AU #define TIM_CHANNEL_4 0x0000000CU
#define TIM_CHANNEL_4n 0x0000000EU #define TIM_CHANNEL_ALL 0x00000018U//定义互补通道
使用基础定时器TIM4进行定时说明
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);
在主程序中加入 HAL_TIM_Base_Start_IT(&htim4);//以中断方式启动定时器
或者加入以下4个宏函数:
vMBPortTimersEnable( )
{
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_SET_COUNTER(&htim4,0);
__HAL_TIM_ENABLE(&htim4); //使能定时器
}
vMBPortTimersDisable( )
{
/* 关闭定时器 */
__HAL_TIM_DISABLE(&htim4);
__HAL_TIM_SET_COUNTER(&htim4,0);
__HAL_TIM_DISABLE_IT(&htim4,TIM_IT_UPDATE);
__HAL_TIM_CLEAR_IT(&htim4,TIM_IT_UPDATE);
}
这个函数处理TIM3全局中断 void TIM3_IRQHandler(void)
在tim.c中加入
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);}
切换pc13的状态
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//在stm32fxx_hal_tim.c中是弱函数存在,必须重写
} 或者在 it.c中加入也可以
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
}//基础定时器只需要选择内部时针
关于串口数据传输
所有的串口ISR都是调用HAL_UART_IRQHandler();这个处理函数,这个函数是中断处理通用函数
这个函数会判断产生中断的事件的类型,清除事件中断的标志位,调用中断事件类型的中断回调函数
标签:__,HAL,UART,void,TIM,freemodbus,stm32f103c8t6,移植,define
From: https://www.cnblogs.com/chshnxht/p/18174042