问答

汇集网友智慧,解决技术难题

21ic问答首页 - GD32E230用捕获及485通讯,开启捕获就通讯卡死且初始化失败

失败 485 通讯 GD32E230 TI ar

GD32E230用捕获及485通讯,开启捕获就通讯卡死且初始化失败

1910506742025-07-05
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;   
       }

}


有类似遇到的问题吗?求解,谢谢



回答 +关注 1
180人浏览 0人回答问题 分享 举报
0 个回答

您需要登录后才可以回复 登录 | 注册