7.28335以时间间隔判断帧

在串行通信中,很难判断帧标志,常用的方法是定长、结束符等方法。定长就是约定好协议字符字节长度,当收到所有字节后开始处理,但是这种方法不适用于不定长的通信。结束符就是约定一定的字符作为判断通信结束的标志,比如常用的回车换行符,0D 0A,但是这种方法会浪费通信资源。

下面介绍一种以时间间隔判断帧,和人说话一样,当一句话说完会进行停顿,这时判断停顿的时间,当一定时间内没有收到数据,就把前面这段时间的数据进行处理。这种方法在MODBUS通信协议中应用较为广泛。

本例程的开发板是普中的PZ-DSP28335-L开发板,串口为SCI-A,定时器为TIMER0。

1.串口初始化

对串口进行初始化,配置SCI-A的波特率,工作方式,使能中断,配置接收中断服务子函数。

定义好发送字符、字符串的函数,还有清除接收BUFFER的函数,方便调用。

在中断服务子函数中,对接收到的数据进行保存到BUFFER,如果是接收的第一个字节,需要打开定时器开始计时。

#include "uart.h"

unsigned char USART2_RX_BUF[USART2_MAX_RECV_LEN];              //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
unsigned char USART2_TX_BUF[USART2_MAX_SEND_LEN];            //发送缓冲,最大USART2_MAX_SEND_LEN字节

volatile Uint16 USART2_RX_STA=0;                          //接收数据状态

void UARTa_Init(Uint32 baud)
{
	unsigned char scihbaud=0;
	unsigned char scilbaud=0;
	Uint16 scibaud=0;

	scibaud=37500000/(8*baud)-1;
	scihbaud=scibaud>>8;
	scilbaud=scibaud&0xff;


	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1;   // SCI-A
	PieVectTable.SCIRXINTA = &sciaRxFifoIsr;
	EDIS;

	InitSciaGpio();

	//Initalize the SCI FIFO
	SciaRegs.SCIFFTX.all=0xE040;
	SciaRegs.SCIFFRX.all=0x2021;//0x204f;
	SciaRegs.SCIFFCT.all=0x0;

	// Note: Clocks were turned on to the SCIA peripheral
	// in the InitSysCtrl() function
	SciaRegs.SCICCR.all =0x0007;   // 1 stop bit,  No loopback
								   // No parity,8 char bits,
								   // async mode, idle-line protocol
	SciaRegs.SCICTL1.all =0x0003;  // enable TX, RX, internal SCICLK,
								   // Disable RX ERR, SLEEP, TXWAKE
	SciaRegs.SCICTL2.all =0x0003;
	SciaRegs.SCICTL2.bit.TXINTENA =1;
	SciaRegs.SCICTL2.bit.RXBKINTENA =1;
	SciaRegs.SCIHBAUD    =scihbaud;  // 9600 baud @LSPCLK = 37.5MHz.
	SciaRegs.SCILBAUD    =scilbaud;
//	SciaRegs.SCICCR.bit.LOOPBKENA =1; // Enable loop back
	SciaRegs.SCICTL1.all =0x0023;     // Relinquish SCI from Reset

	ResetRxbuf();

    PieCtrlRegs.PIECTRL.bit.ENPIE=1;
    PieCtrlRegs.PIEIER9.bit.INTx1=1;
    IER|=M_INT9;

}

void ResetRxbuf(void)
{
    int i;
    for(i=0;i<USART2_MAX_RECV_LEN;i++)
    {
        USART2_RX_BUF[i] = 0;
    }
}
// Transmit a character from the SCI'
void UARTa_SendByte(int a)
{
	while (SciaRegs.SCIFFTX.bit.TXFFST != 0);
	SciaRegs.SCITXBUF=a;
}

void UARTa_SendString(unsigned char * msg)
{
	int i=0;

	while(msg[i] != '\0')
	{
		UARTa_SendByte(msg[i]);
		i++;
	}
}

interrupt void sciaRxFifoIsr(void)
{
    Uint16 data;
    data = (SciaRegs.SCIRXBUF.all)&0xff;  // Read data

    if((USART2_RX_STA&0x8000)==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
    {
        if(USART2_RX_STA<USART2_MAX_RECV_LEN)   //还可以接收数据
        {
            //CpuTimer0.RegsAddr->TIM.all = 0;//计数器清空                          //计数器清空
            CpuTimer0Regs.TIM.all  = 0;
            if(USART2_RX_STA==0)                //使能定时器7的中断
            {
                CpuTimer0Regs.TCR.bit.TSS=0;
            }
            USART2_RX_BUF[USART2_RX_STA]=data; //记录接收到的值
            USART2_RX_STA++;
        }else
        {
            USART2_RX_STA |= 0x8000;               //强制标记接收完成
        }
    }

    SciaRegs.SCIFFRX.bit.RXFFOVRCLR=1;   // Clear Overflow flag
    SciaRegs.SCIFFRX.bit.RXFFINTCLR=1;   // Clear Interrupt flag

    PieCtrlRegs.PIEACK.all |= PIEACK_GROUP9;       // Issue PIE ack
}

#ifndef UART_H_
#define UART_H_

#include "DSP2833x_Device.h"     // DSP2833x 头文件
#include "DSP2833x_Examples.h"   // DSP2833x 例子相关头文件

#define USART2_MAX_RECV_LEN     400                 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN     400                 //最大发送缓存字节数

#define UART_AUTOBAUN_TEST

extern unsigned char  USART2_RX_BUF[USART2_MAX_RECV_LEN];      //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern unsigned char  USART2_TX_BUF[USART2_MAX_SEND_LEN];      //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern volatile Uint16 USART2_RX_STA;                          //接收数据状态

void ResetRxbuf(void);
void UARTa_Init(Uint32 baud);
void UARTa_SendByte(int a);
void UARTa_SendString(unsigned char * msg);


interrupt void sciaRxFifoIsr(void);

#endif /* UART_H_ */

2.定时器初始化

配置定时器为10ms,时间间隔可以根据需求进行更改,一般是3个字符通信时间以上。配置好定时器后,不要开启定时器,由串口接收到第一个字节数据后开启定时器。

在定时器中断服务函数中,直接对接收完成标志进行置位。

#include "timer.h"
#include "leds.h"
#include "smg.h"
#include "uart.h"

void TIM0_Init(float Freq, float Period)
{
	EALLOW;
	SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0
	EDIS;

	EALLOW;
	PieVectTable.TINT0 = &TIM0_IRQn;
	EDIS;

	// CPU Timer 0
	// Initialize address pointers to respective timer registers:
	CpuTimer0.RegsAddr = &CpuTimer0Regs;
	// Initialize timer period to maximum:
	CpuTimer0Regs.PRD.all  = 0xFFFFFFFF;
	// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
	CpuTimer0Regs.TPR.all  = 0;
	CpuTimer0Regs.TPRH.all = 0;
	// Make sure timer is stopped:
	CpuTimer0Regs.TCR.bit.TSS = 1;
	// Reload all counter register with period value:
	CpuTimer0Regs.TCR.bit.TRB = 1;
	// Reset interrupt counters:
	CpuTimer0.InterruptCount = 0;

	ConfigCpuTimer(&CpuTimer0, Freq, Period);

//	CpuTimer0Regs.TCR.bit.TSS=0;

	IER |= M_INT1;

	PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

	EINT;
	ERTM;

}

interrupt void TIM0_IRQn(void)
{
	EALLOW;
	//LED1_TOGGLE;
	//SMG_Display();
	USART2_RX_STA |= 0x8000;   //标记接收完成
	CpuTimer0Regs.TCR.bit.TSS=1;
	PieCtrlRegs.PIEACK.bit.ACK1=1;
	EDIS;
}
#ifndef TIME_H_
#define TIME_H_


#include "DSP2833x_Device.h"     // DSP2833x 头文件
#include "DSP2833x_Examples.h"   // DSP2833x 例子相关头文件



void TIM0_Init(float Freq, float Period);
interrupt void TIM0_IRQn(void);

void TIM1_Init(float Freq, float Period);
interrupt void TIM1_IRQn(void);

void TIM2_Init(float Freq, float Period);
interrupt void TIM2_IRQn(void);


#endif /* TIME_H_ */

3.处理函数

在主函数里面判断接收标志,如果接收完成,则完成对应的处理函数。

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File

#include "leds.h"
#include "key.h"
#include "timer.h"
#include "uart.h"
#include "str.h"

unsigned char str[20];//define a string, for the string of distance, send to PC

void main(void)
{
    InitSysCtrl();//initialize system control register

    InitPieCtrl();//initialize PIE control register
    IER = 0x0000;//all interrupt disable
    IFR = 0x0000;//all interrupt flag clear
    InitPieVectTable();//initialize PIE service subfunction

    UARTa_Init(115200);//initialize SCI-A,baud is 115200
    LED_Init();//initialize LED GPIO,The LED flashes to indicate that the program is running
    KEY_Init();//initialize KEY GPIO

    TIM0_Init(150,10000);//initialize timer0,Complete time interval judgment frame with serial port

    UARTa_SendString("RESTARTED\r\n");

    while(1)
    {
        if(USART2_RX_STA & 0X8000) //Received Data
        {
            UARTa_SendString("received");
            Num2Str(str,USART2_RX_STA&0x7FFF,3);
            UARTa_SendString(str);
            UARTa_SendString("data:");
            UARTa_SendString(USART2_RX_BUF);
            UARTa_SendString("\r\n");
            ResetRxbuf();
            USART2_RX_STA = 0;
        }
    }
}

本例中的操作是,完成后发送当前收到的数据量,然后将数据打包发回。

4.程序开源

本次例程代码

链接:https://pan.baidu.com/s/1WuBAQnranvqym2AUq9g4XQ

提取码:t0sc

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页