21ic问答首页 - GD32E230用捕获及485通讯,开启捕获就通讯卡死且初始化失败
GD32E230用捕获及485通讯,开启捕获就通讯卡死且初始化失败
GD32E230C8T6 用TIMER2_CH3进行频率捕获,同时用USART0进行485通讯,一开启捕获就通讯不了,且一点仿真DEBUG按钮就直接全速运行,然后就卡死在LDR R0, =SystemInit位置,无法初始化。具体代码如下:
int main(void){
systick_config(); //滴答定时器初始化
Led_Gpio_Init(); //数码管引脚初始化
Key_Init(); //按键引脚初始化
Relay_GPIO_Init(); //继电器引脚初始化
Capture_Gpio_config(); //捕获引脚初始化
usart_config(9600); //串口配置
Para_Read(); //读取参数
LedPower = 1; //电源灯亮
Adc_gpio_config(); //ADC采样引脚初始化
Adc_Config(); //ADC参数配置初始化
Nvic_config(); //捕获中断
Timer2_config(); //Timer2配置
Timer5_Init(3600,40); //定时10ms = 3600/72M *200
Timer14_Init(36,625); //定时312.5us
while(1)
{
Adc_Cal(); //ADC采样计算
fre_capture_cal();
KeyMake(); //按键动作
Protect();
Display(); //显示
UartDriver();
}
}
void Capture_Gpio_config(void)
{
/* 使能GPIOB时钟 */
rcu_periph_clock_enable(RCU_GPIOB);
/* 配置PB1(TIMER2_CH3)为复用功能 */
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_1); // 根据数据手册选择正确的AF
}
/*
*********************************************************************************************************
* 函 数 名: nvic_config
* 功能说明: 配置中断优先级
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void Nvic_config(void)
{
nvic_irq_enable(TIMER2_IRQn,0);
}
/*
*********************************************************************************************************
* 函 数 名: timer2_config
* 功能说明: 定时器配置--捕获
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void Timer2_config(void)
{
timer_ic_parameter_struct timer_icinitpara;
timer_parameter_struct timer_initpara;
/* enable the TIMER clock */
rcu_periph_clock_enable(RCU_TIMER2);
/* disable a TIMER */
timer_deinit(TIMER2);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 7199;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 65535;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER2, &timer_initpara);
/* TIMER2 configuration */
/* initialize TIMER channel input parameter struct */
timer_channel_input_struct_para_init(&timer_icinitpara);
/* TIMER2 CH3 input capture configuration */
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; //此处采用下降沿捕获, TIMER_IC_POLARITY_RISING
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
timer_icinitpara.icfilter = 0x0;
timer_input_capture_config(TIMER2,TIMER_CH_3,&timer_icinitpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER2);
/* clear channel 3 interrupt bit */
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH3 );
/* clear channel 3 interrupt bit */
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP );
/* channel 3 interrupt enable */
timer_interrupt_enable(TIMER2,TIMER_INT_CH3);
/* channel 3 interrupt enable */
timer_interrupt_enable(TIMER2,TIMER_INT_UP);
/* TIMER2 counter enable */
timer_enable(TIMER2);
}
/*
*********************************************************************************************************
* 函 数 名: TIM2_IRQHandler
* 功能说明: TIM2 中断服务程序
* 形 参:无
* 返 回 值: 无 1us
*********************************************************************************************************
*/
void TIMER2_IRQHandler(void)
{
if(timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_CH3))
{
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH3); //清除TIMER2的中断标志
uint32_t currentCapture = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_3);
if(firstCapture)
{
lastCapture = currentCapture;
firstCapture = 0;
}
else
{
capture_diff = (currentCapture - lastCapture) +(overflow_count * 65536);
test_flag = 1; //置位测量标志
lastCapture = currentCapture;
}
overflow_count = 0;
}
if(timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_UP))
{
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP);
overflow_count ++;
}
}
void fre_capture_cal(void)
{
if(test_flag)
{
test_flag = 0;
frequency = 10000.0f/capture_diff;
MeasData.freq = (uint32_t)(frequency*10); //频率转换
}
if(MeasData.Uln < 50) //小于5V
{
MeasData.freq = 0;
}
}
void usart_config(uint32_t band_rate)
{
rcu_periph_clock_enable(RCU_GPIOA); // 开启引脚端口时钟 PA9 TX PA10 RX
rcu_periph_clock_enable(RCU_USART0); // 开启串口时钟
/* 配置GPIO复用功能 */
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
/* 配置PA9 TX为复用模式 上拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
/* 配置PA10 RX为复用模式 无上拉下拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
/* 配置RX为浮空输入 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* 配置DE为输出模式 无上拉下拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11); //485
/* 配置DE为推挽输出 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11); //485
RS485_DE(0); //使能接收 485
usart_deinit(USART0); // 复位串口
usart_baudrate_set(USART0,band_rate); // 设置波特率
usart_parity_config(USART0,USART_PM_NONE); // 没有校验位
usart_word_length_set(USART0,USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(USART0,USART_STB_2BIT); // 2位停止位
/* 使能串口 */
usart_receive_config(USART0,USART_RECEIVE_ENABLE); // 使能串口接收
usart_transmit_config(USART0,USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receiver_timeout_threshold_config(USART0,100); //设置串口接收超时阈值,这个100是指100bit时间,如果按照10bit传输一个字节,那么就是10个字节时间
usart_receiver_timeout_enable(USART0); //超时使能
usart_enable(USART0); // 使能串口
nvic_irq_enable(USART0_IRQn,0);
usart_interrupt_enable(USART0, USART_INT_RBNE); // 使能接收中断
usart_interrupt_enable(USART0, USART_INT_RT); //使能串口接收超时中断
}
void usart_send(uint8_t *buf, uint8_t len)
{
uint8_t i;
while(tx_busy); //等待上一个发送完成
tx_busy = 1; //准备发送
RS485_DE(1); //发送模式
usart_interrupt_disable(USART0, USART_INT_RBNE|USART_INT_RT); // 禁能接收中断(避免发送期间接收自己的数据)
for(i=0; i<len; i++)
{
usart_data_transmit(USART0,buf[i]); // 发送数据
delay_ms(10);
while(RESET == usart_flag_get(USART0,USART_FLAG_TBE)); // 等待发送数据寄存器空标志置位 判断是否发送数据发送到移位寄存器,若reset = 0,则表示还没有发送到移位寄存器,那就一直循环;reset=1,则
}
while(RESET== usart_flag_get(USART0,USART_FLAG_TC)); //等待发送完成
RS485_DE(0); //接收模式
usart_interrupt_enable(USART0, USART_INT_RBNE|USART_INT_RT); // 使能接收中断(避免发送期间接收自己的数据)
tx_busy = 0;
}
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) //读取数据缓冲区不为空标志
{
g_recv_buff[g_recv_length] = usart_data_receive(USART0);
g_recv_length++;
if(g_recv_length >= sizeof(g_recv_buff))
{
g_recv_length = 0;
}
}
else if(RESET != usart_interrupt_flag_get(USART0,USART_INT_FLAG_RT)) //接收中断超时标志
{
usart_flag_clear(USART0,USART_FLAG_RT);
g_recv_complete_flag = 1;
}
}
void UartDriver(void)
{
uint8_t len;
uint8_t buf[64] = {0x00}; //接收数据存放的数组
if(g_recv_complete_flag ==1)
{
g_recv_complete_flag = 0;
process_modbus_request();
g_recv_length = 0;
}
}
void process_modbus_request(void)
{
uint16_t i = 0;
uint16_t j = 0;
uint16_t crc = 0; //校验码
uint8_t crch = 0; //校验码高字节
uint8_t crcl = 0; //校验码低字节
uint16_t addr = 0; //寄存器地址
uint16_t cnt = 0; //数据量
uint16_t data = 0; //写入的数据
uint16_t addrtemp = 0;
uint16_t index;
if(g_recv_buff[0] != Para.Addr )
{return;}
crc = usMBCRC16(g_recv_buff,g_recv_length-2); //校验码
crch = (uint8_t)(crc >>8); //取高8位
crcl = (uint8_t)crc; //取低位
if((g_recv_buff[g_recv_length-2]!=crch)||(g_recv_buff[g_recv_length-1]!=crcl)) //校验码不对
{
return ; //返回空白值
}
addr = ((uint16_t)g_recv_buff[2]<<8)|g_recv_buff[3]; //寄存器地址
switch(g_recv_buff[1])
{
/*03功能码 读单个寄存器*/
case 0x03:
cnt= ((uint16_t)g_recv_buff[4]<<8)|g_recv_buff[5];
if(cnt==0) //数据量=0
{
Errcmd_addr_data(g_recv_buff,3); //返回数据错误码 03
return;
}
if((addr >= 0x0A00)&&(addr <= 0x0A04)) //地址范围0x0a00--0x0a06
{
if((addr+cnt) > 0x0A05)
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& MeasData.Uln +(addr & 0x00FF)+i)>>8); //取高8位数据 (uint8_t)强制转换为uint8_t类型的数据;*取后面括号里的数据 (uint32_t*)把Uln的地址强制转化为uint32_t类型指针 &取Uln的地址
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& MeasData.Uln +(addr & 0x00FF)+i)); //取低8位数据
}
}
}
else if((addr >= 0x0B00)&&(addr <= 0x0B13)) //地址范围0x0b00--0x0b07
{
if(((addr+cnt) > 0x0B14)||(addr%2 !=0)) //超出地址、地址不等于8的倍数 则报错
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
if((addr + i - 0x0b00)%2 ==0)
{
index = ( addr + i - 0x0b00) /2; //8为故障记录字节数
index = (index % 10 )+1; //10为记录数10条
if(ErrRecord_Read(index, &Err_ASK) == 1) //读通讯故障记录
{
Err_ASK.ErrType =0;
Err_ASK.ErrValue =0;
}
}
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& Err_ASK.ErrType +((addr & 0x00FF)+i)%2)>>8); //取高8位数据
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& Err_ASK.ErrType +((addr & 0x00FF)+i)%2)); //取低8位数据
}
}
}
else if((addr >= 0x0C00)&&(addr <= 0x0C0B)) //地址范围0x0C00--0x0C0B
{
if((addr+cnt) > 0x0C0C)
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,则报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& Para.Mode +(addr & 0x00FF)+i)>>8); //取高8位数据
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& Para.Mode +(addr & 0x00FF)+i)); //取低8位数据
}
}
}
else //地址不在范围内,报82错误码
{
Errcmd_addr_data(g_recv_buff,2);
return;
}
txbuffer[0] = Para.Addr; //设备地址
txbuffer[1] = 0x03; //功能码
txbuffer[2] = cnt*2; //读出的字节数
crc = usMBCRC16(txbuffer,cnt*2+3); //CRC校验值计算
crch = (uint8_t)(crc >> 8);
crcl = (uint8_t)crc;
txbuffer[3 + cnt * 2] = crch; //CRC高位数据地址
txbuffer[4 + cnt * 2] = crcl; //CRC低位数据地址
usart_send(txbuffer,cnt*2+5); //发送
break;
default:
Errcmd_addr_data(g_recv_buff,1); //错误码01
break;
}
}
有类似遇到的问题吗?求解,谢谢
int main(void){
systick_config(); //滴答定时器初始化
Led_Gpio_Init(); //数码管引脚初始化
Key_Init(); //按键引脚初始化
Relay_GPIO_Init(); //继电器引脚初始化
Capture_Gpio_config(); //捕获引脚初始化
usart_config(9600); //串口配置
Para_Read(); //读取参数
LedPower = 1; //电源灯亮
Adc_gpio_config(); //ADC采样引脚初始化
Adc_Config(); //ADC参数配置初始化
Nvic_config(); //捕获中断
Timer2_config(); //Timer2配置
Timer5_Init(3600,40); //定时10ms = 3600/72M *200
Timer14_Init(36,625); //定时312.5us
while(1)
{
Adc_Cal(); //ADC采样计算
fre_capture_cal();
KeyMake(); //按键动作
Protect();
Display(); //显示
UartDriver();
}
}
void Capture_Gpio_config(void)
{
/* 使能GPIOB时钟 */
rcu_periph_clock_enable(RCU_GPIOB);
/* 配置PB1(TIMER2_CH3)为复用功能 */
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_1); // 根据数据手册选择正确的AF
}
/*
*********************************************************************************************************
* 函 数 名: nvic_config
* 功能说明: 配置中断优先级
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void Nvic_config(void)
{
nvic_irq_enable(TIMER2_IRQn,0);
}
/*
*********************************************************************************************************
* 函 数 名: timer2_config
* 功能说明: 定时器配置--捕获
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void Timer2_config(void)
{
timer_ic_parameter_struct timer_icinitpara;
timer_parameter_struct timer_initpara;
/* enable the TIMER clock */
rcu_periph_clock_enable(RCU_TIMER2);
/* disable a TIMER */
timer_deinit(TIMER2);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 7199;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 65535;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER2, &timer_initpara);
/* TIMER2 configuration */
/* initialize TIMER channel input parameter struct */
timer_channel_input_struct_para_init(&timer_icinitpara);
/* TIMER2 CH3 input capture configuration */
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; //此处采用下降沿捕获, TIMER_IC_POLARITY_RISING
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
timer_icinitpara.icfilter = 0x0;
timer_input_capture_config(TIMER2,TIMER_CH_3,&timer_icinitpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER2);
/* clear channel 3 interrupt bit */
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH3 );
/* clear channel 3 interrupt bit */
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP );
/* channel 3 interrupt enable */
timer_interrupt_enable(TIMER2,TIMER_INT_CH3);
/* channel 3 interrupt enable */
timer_interrupt_enable(TIMER2,TIMER_INT_UP);
/* TIMER2 counter enable */
timer_enable(TIMER2);
}
/*
*********************************************************************************************************
* 函 数 名: TIM2_IRQHandler
* 功能说明: TIM2 中断服务程序
* 形 参:无
* 返 回 值: 无 1us
*********************************************************************************************************
*/
void TIMER2_IRQHandler(void)
{
if(timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_CH3))
{
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH3); //清除TIMER2的中断标志
uint32_t currentCapture = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_3);
if(firstCapture)
{
lastCapture = currentCapture;
firstCapture = 0;
}
else
{
capture_diff = (currentCapture - lastCapture) +(overflow_count * 65536);
test_flag = 1; //置位测量标志
lastCapture = currentCapture;
}
overflow_count = 0;
}
if(timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_UP))
{
timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP);
overflow_count ++;
}
}
void fre_capture_cal(void)
{
if(test_flag)
{
test_flag = 0;
frequency = 10000.0f/capture_diff;
MeasData.freq = (uint32_t)(frequency*10); //频率转换
}
if(MeasData.Uln < 50) //小于5V
{
MeasData.freq = 0;
}
}
void usart_config(uint32_t band_rate)
{
rcu_periph_clock_enable(RCU_GPIOA); // 开启引脚端口时钟 PA9 TX PA10 RX
rcu_periph_clock_enable(RCU_USART0); // 开启串口时钟
/* 配置GPIO复用功能 */
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
/* 配置PA9 TX为复用模式 上拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
/* 配置TX为推挽输出 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
/* 配置PA10 RX为复用模式 无上拉下拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
/* 配置RX为浮空输入 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* 配置DE为输出模式 无上拉下拉模式 */
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11); //485
/* 配置DE为推挽输出 50MHZ */
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11); //485
RS485_DE(0); //使能接收 485
usart_deinit(USART0); // 复位串口
usart_baudrate_set(USART0,band_rate); // 设置波特率
usart_parity_config(USART0,USART_PM_NONE); // 没有校验位
usart_word_length_set(USART0,USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(USART0,USART_STB_2BIT); // 2位停止位
/* 使能串口 */
usart_receive_config(USART0,USART_RECEIVE_ENABLE); // 使能串口接收
usart_transmit_config(USART0,USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receiver_timeout_threshold_config(USART0,100); //设置串口接收超时阈值,这个100是指100bit时间,如果按照10bit传输一个字节,那么就是10个字节时间
usart_receiver_timeout_enable(USART0); //超时使能
usart_enable(USART0); // 使能串口
nvic_irq_enable(USART0_IRQn,0);
usart_interrupt_enable(USART0, USART_INT_RBNE); // 使能接收中断
usart_interrupt_enable(USART0, USART_INT_RT); //使能串口接收超时中断
}
void usart_send(uint8_t *buf, uint8_t len)
{
uint8_t i;
while(tx_busy); //等待上一个发送完成
tx_busy = 1; //准备发送
RS485_DE(1); //发送模式
usart_interrupt_disable(USART0, USART_INT_RBNE|USART_INT_RT); // 禁能接收中断(避免发送期间接收自己的数据)
for(i=0; i<len; i++)
{
usart_data_transmit(USART0,buf[i]); // 发送数据
delay_ms(10);
while(RESET == usart_flag_get(USART0,USART_FLAG_TBE)); // 等待发送数据寄存器空标志置位 判断是否发送数据发送到移位寄存器,若reset = 0,则表示还没有发送到移位寄存器,那就一直循环;reset=1,则
}
while(RESET== usart_flag_get(USART0,USART_FLAG_TC)); //等待发送完成
RS485_DE(0); //接收模式
usart_interrupt_enable(USART0, USART_INT_RBNE|USART_INT_RT); // 使能接收中断(避免发送期间接收自己的数据)
tx_busy = 0;
}
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) //读取数据缓冲区不为空标志
{
g_recv_buff[g_recv_length] = usart_data_receive(USART0);
g_recv_length++;
if(g_recv_length >= sizeof(g_recv_buff))
{
g_recv_length = 0;
}
}
else if(RESET != usart_interrupt_flag_get(USART0,USART_INT_FLAG_RT)) //接收中断超时标志
{
usart_flag_clear(USART0,USART_FLAG_RT);
g_recv_complete_flag = 1;
}
}
void UartDriver(void)
{
uint8_t len;
uint8_t buf[64] = {0x00}; //接收数据存放的数组
if(g_recv_complete_flag ==1)
{
g_recv_complete_flag = 0;
process_modbus_request();
g_recv_length = 0;
}
}
void process_modbus_request(void)
{
uint16_t i = 0;
uint16_t j = 0;
uint16_t crc = 0; //校验码
uint8_t crch = 0; //校验码高字节
uint8_t crcl = 0; //校验码低字节
uint16_t addr = 0; //寄存器地址
uint16_t cnt = 0; //数据量
uint16_t data = 0; //写入的数据
uint16_t addrtemp = 0;
uint16_t index;
if(g_recv_buff[0] != Para.Addr )
{return;}
crc = usMBCRC16(g_recv_buff,g_recv_length-2); //校验码
crch = (uint8_t)(crc >>8); //取高8位
crcl = (uint8_t)crc; //取低位
if((g_recv_buff[g_recv_length-2]!=crch)||(g_recv_buff[g_recv_length-1]!=crcl)) //校验码不对
{
return ; //返回空白值
}
addr = ((uint16_t)g_recv_buff[2]<<8)|g_recv_buff[3]; //寄存器地址
switch(g_recv_buff[1])
{
/*03功能码 读单个寄存器*/
case 0x03:
cnt= ((uint16_t)g_recv_buff[4]<<8)|g_recv_buff[5];
if(cnt==0) //数据量=0
{
Errcmd_addr_data(g_recv_buff,3); //返回数据错误码 03
return;
}
if((addr >= 0x0A00)&&(addr <= 0x0A04)) //地址范围0x0a00--0x0a06
{
if((addr+cnt) > 0x0A05)
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& MeasData.Uln +(addr & 0x00FF)+i)>>8); //取高8位数据 (uint8_t)强制转换为uint8_t类型的数据;*取后面括号里的数据 (uint32_t*)把Uln的地址强制转化为uint32_t类型指针 &取Uln的地址
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& MeasData.Uln +(addr & 0x00FF)+i)); //取低8位数据
}
}
}
else if((addr >= 0x0B00)&&(addr <= 0x0B13)) //地址范围0x0b00--0x0b07
{
if(((addr+cnt) > 0x0B14)||(addr%2 !=0)) //超出地址、地址不等于8的倍数 则报错
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
if((addr + i - 0x0b00)%2 ==0)
{
index = ( addr + i - 0x0b00) /2; //8为故障记录字节数
index = (index % 10 )+1; //10为记录数10条
if(ErrRecord_Read(index, &Err_ASK) == 1) //读通讯故障记录
{
Err_ASK.ErrType =0;
Err_ASK.ErrValue =0;
}
}
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& Err_ASK.ErrType +((addr & 0x00FF)+i)%2)>>8); //取高8位数据
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& Err_ASK.ErrType +((addr & 0x00FF)+i)%2)); //取低8位数据
}
}
}
else if((addr >= 0x0C00)&&(addr <= 0x0C0B)) //地址范围0x0C00--0x0C0B
{
if((addr+cnt) > 0x0C0C)
{
Errcmd_addr_data(g_recv_buff,3); //字节数超范围,则报83错误码
return;
}
else
{
for(i=0;i<cnt;i++)
{
txbuffer[3+i*2] = (uint8_t)(*((uint32_t*)& Para.Mode +(addr & 0x00FF)+i)>>8); //取高8位数据
txbuffer[4+i*2] = (uint8_t)(*((uint32_t*)& Para.Mode +(addr & 0x00FF)+i)); //取低8位数据
}
}
}
else //地址不在范围内,报82错误码
{
Errcmd_addr_data(g_recv_buff,2);
return;
}
txbuffer[0] = Para.Addr; //设备地址
txbuffer[1] = 0x03; //功能码
txbuffer[2] = cnt*2; //读出的字节数
crc = usMBCRC16(txbuffer,cnt*2+3); //CRC校验值计算
crch = (uint8_t)(crc >> 8);
crcl = (uint8_t)crc;
txbuffer[3 + cnt * 2] = crch; //CRC高位数据地址
txbuffer[4 + cnt * 2] = crcl; //CRC低位数据地址
usart_send(txbuffer,cnt*2+5); //发送
break;
default:
Errcmd_addr_data(g_recv_buff,1); //错误码01
break;
}
}
有类似遇到的问题吗?求解,谢谢
您需要登录后才可以回复 登录 | 注册