分支数据监测终端(从UART配置开始 添加TCBUS事件清除功能)


前言:记录一下将定时器延时实现的TCBUS清除事件功能

1、UART发送报文起始位、校验位以及停止位的配置

报文:

INT8U CLEAR_alarm_state[7] = {
    
    0x7F,0xFB,0xF7,0x01,0x63,0xF0,0xA5};

1.1.帧格式

  在发送数据之前需要先配置好起始位、校验位以及停止位,当按字节传输时先传低位后传高位,其格式如图2-3 所示,我们称之为一个帧字符(Frame Character,FC)。每个帧字符包括1 位起始位(0)、8 位信息位、1 位偶校验位(E)和1~2 位停止位(1);其中,发码设置帧字符12 位,收码设置帧字符11 位。

1.2.字符格式

在这里插入图片描述
其中起始位、校验位以及停止位的配置是在函数初始化里面进行的:drv_uart_init(2,2400,USART_8E2);
PLIB_USART_LineControlModeSelect(usart_id, uartMode);
在这里插入图片描述
  掩码是0x06 : 0110 表示 bit 2-1 写入寄存器的值value=1 位置pos为1 :1左移1位&掩码 0110 等于0010,bit 2-1就被赋值为“ 01 ”,对应上图数据手册“ 01 ”表示偶校验。

/*
  Parameters:
    reg - SFR register name.SFR寄存器名。
    mask - field bit mask within the register.寄存器内的字段位掩码。
    pos - bit position within register.寄存器内位的位置。
    val - new value of field, with the LSb justified to be at bit zero.字段的新值,LSb对齐为零位。
*/    
#define _SFR_FIELD_WRITE(reg,mask,pos,val)  \ 
   (  *((SFR_TYPE *)(reg)) = \
        ( (*((SFR_TYPE *)(reg))) & ~(mask) ) | ( (mask)&((val)<<(pos)) )  )

  校验位pos=0,表示bit0为“1”表示两个停止位,可能起始位默认都是1位的无需配置。(没有配置起始位和停止位的电平估计是默认起始位为低,停止位为高吧)

#define _SFR_BIT_SET(reg,pos)        ( *((SFR_TYPE *)((reg)+(2))) = 1<<(pos) )

1.3.小结

  寄存器的配置某一位的数值是通过函数:_SFR_BIT_SET(reg,pos) 配置寄存器某一位为1或者_SFR_BIT_CLEAR(reg,pos)某一位为0;
  多个位配置就要函数_SFR_FIELD_WRITE(reg,mask,pos,val)需要掩码mask,位置pos以及要配置的数值val(0/1)。

2、发送事件清除报文

  在TCBUS协议传感器注册之前,先用定时器延时100ms,然后TCBUS总线发送清事件报文(包括一字节的时钟同步码(7F)3500um的时钟同步延时,7字节的事件清除报文),欲实现效果如下图:
在这里插入图片描述

2.1 逻辑思路

  在系统初始化函数中SYS_Initialize()配置程序起点,现将TCBUS总线置为接收态(5V),再使能引脚接收功能,判断过流引脚是否过流,须知:TCBUS芯片与MCU连接主要有4根线(R/T收发控制、RX、TX以及过流检测引脚),0==read_Tcbus_EO_state()表示过流检测引脚检测到过流,0 ==read_TCBUS_state()表示总线与地短路,如果终端开机检测到TCBUS短路则不启动正常的注册流程,若没短路走else正常启动流程,将总线状态置为发送态(24V)将定时器初值设定为500um进入一次中断处理函数,配置当前switch的状态为tcbus_state,定义一个全局延时计数器:delay_500us_count在中断处理函数中加1,实现延时500um的delay_500us_count倍,每进一次终端延时计数器减一,直到延时计数器清零,延时结束跳到下一个状态next_tcbus_state。

代码实现:

#ifdef __TCBUS_VERSION__
    drv_tcbus_dir(TCBUS_DIR_RECE);//启动时,    
    if_soft_rs485_open(9600);
    drv_uart2_rece_ctl(1);
    if((0==read_Tcbus_EO_state()) || (0==read_TCBUS_state()))
    {
    
    
        stop_read_tcbus_flag = 1;
        need_tcbus_init_flag = 0;
    }
    else 
    {
    
    
        tpos_clrTaskWdt();
        drv_tcbus_dir(TCBUS_DIR_SEND);
        delay_500us_count = 200;
        tcbus_state =100;
        next_tcbus_state = 1;
        _drv_adc_trig_tmr2.trig_value = SYS_FREQ/8/1000 - 1;//  500us 
        _drv_adc_trig_tmr2.tmr_isr_callback = tcbus_timer2;
        drv_tmr_config(&_drv_adc_trig_tmr2);
        drv_tmr_int_enable(&_drv_adc_trig_tmr2);
        drv_tmr_start(&_drv_adc_trig_tmr2); 
    }

  其中drv_tmr_config(); drv_tmr_int_enable(); drv_tmr_start(); 三个函数负责定时器延时的配置(根据不同波特率具体延时时长不变就是在这里配置的),定时器的使能,以及定时器的开启。下附定时器初值的配置方法:
在这里插入图片描述
题外知识点:
  系统时钟为Fosc,它是以输入频率作为基础,再依此作除频、倍频、PLL等等,产生出处理器与主板各部分所需的频率。它的输出频率稳定度是由输入频率决定的。因此,时钟芯片如要有精确、稳定的输出,就需要精确、稳定的输入,这就需要用到晶振了。
  定时器开启以后,待延时500um以后,系统运行到定时器处理函数:tcbus_timer2(); 其中tcbus_timer2()是定时器中断触发的回调函数tmr_isr_callback,函数名以及函数内容均可以自行配置。

void __attribute__((interrupt(IPL3AUTO), vector(_TIMER_2_VECTOR)))Timer2Handler(void)//TCBUS
{
    
    
    // Clear the interrupt flag
    PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_TIMER_2);

    if ((NULL != tmr_para_p[1])&&(NULL != (tmr_para_p[1]->tmr_isr_callback)))
    {
    
    
        tmr_para_p[1]->tmr_isr_callback();
    }
}
case 100:
    delay_500us_count--;
    if(1 == delay_500us_count)
    {
    
    
        tcbus_state = next_tcbus_state;	
    }				
    break;

  待延时(200-1)*500um以后定时器再次进入中断处理函数tcbus_timer2(); 回跳到下一个状态tcbus_state = next_tcbus_state;
  综上,实现了100ms的定时器准确延时。进一步地,再次进入定时器跳转到 case 1,先关闭定时器,初始化串口drv_uart_init(),将波特率和欲配置的校验位、停止位信息配置进去(USART_8E2),然后将发送报文drv_uart2_write(INT8U *data, INT16U length)。

代码实现:

switch(tcbus_state)
{
    
    
	case 1:
		 drv_tmr_stop(&_drv_adc_trig_tmr2);
		 drv_uart_init(2,2400,USART_8E2);
		 drv_uart2_write(buffer_7f,1);
		 break;
	case 2:
	     drv_tmr_stop(&_drv_adc_trig_tmr2);
	     drv_uart_init(2,9600,USART_8E2);
	     drv_uart2_write(CLEAR_alarm_state,7);              
	     break;
	case 100:
	    delay_500us_count--;
	    if(1 == delay_500us_count)
	    {
    
    
	        tcbus_state = next_tcbus_state;	
	    }				
	    break;
	default:
        break;
}

  串口发送以后进入串口发送完成中断函数uart2_Tx_int_Handler()

猜你喜欢

转载自blog.csdn.net/luopeng12345/article/details/111588470