本人使用SCI的通讯经历也不多,仅仅是用于DSP与威纶通公司的触摸屏进行过简单的通讯,通讯方式为RS485,通讯协议为ModbusRTU。
说到SCI,一开始我弄这个的时候,也不懂,网上看了很多资料,但也没有特别合适的,我现在公司的DSP的代码架构,都是一个主中断,一个主循环,一个1ms定时器中断,所以通讯函数,要么放主循环或1ms中断中运行,不会为SCI单独弄个中断,但我这边也不想用《手把手教你学DSP--基于TMS320X281x》上描述的简单SCI查询方式通讯,因为这种方法FIFO没有用,会造成对CPU资源的浪费。
所以我现在提的SCI通讯方式是基于FIFO的轮询方式,以这种方式来配置寄存器,从而形成的读写函数。但28069的SCI的FIFO只有4级,28377D的FIFO有16级。RS485是读写是不能够同时进行的,具体特点,可以百度,这跟RS232不相同。RS485的读写函数是基于ADM2587EBRWZ芯片而写,除了SCI的RX与TX引脚,还多了一个DIR引脚,DIR引脚为高,SCI能够发送数据,反之,读取数据。
代码:
void InitScia(void) // LSPCLK = SYSCLKOUT/4 = 20Mhz
{
SciaRegs.SCICCR.all = 0x07; //1 stopbit,no parity,
//idle line mode,loopback test disable
SciaRegs.SCIHBAUD = 0x10; //20M baud 9600 BBR = 0x103
// BBR = LSPCLK/(波特率*8) - 1
SciaRegs.SCILBAUD = 0x3;
SciaRegs.SCICTL1.all = 0x0003; // enable TX, RX, internal SCICLK,
// Disable RX ERR, SLEEP, TXWAKE
SciaRegs.SCICTL2.all = 0;
SciaRegs.SCIFFTX.all = 0xE040;
SciaRegs.SCIFFRX.all = 0x2040;
SciaRegs.SCIPRI.bit.SOFT = 1; //Complete current receive/transmit
//sequence before stopping
SciaRegs.SCIPRI.bit.FREE = 0;
SciaRegs.SCICTL1.bit.SWRESET = 1;
}
void InitScib(void)
{
ScibRegs.SCICCR.all = 0x07; //1 stopbit,no parity,
//idle line mode,loopback test disable
ScibRegs.SCIHBAUD = 0x10; //20M baud 9600 BBR = 0x103
//BBR = LSPCLK/(波特率*8) - 1
ScibRegs.SCILBAUD = 0x3;
ScibRegs.SCICTL1.all = 0x0003; // enable TX, RX, internal SCICLK,
// Disable RX ERR, SLEEP, TXWAKE
ScibRegs.SCICTL2.all = 0;
ScibRegs.SCIFFTX.all = 0xE040;
ScibRegs.SCIFFRX.all = 0x2040;
ScibRegs.SCIPRI.bit.SOFT = 1; //Complete current receive/transmit
// sequence before stopping
ScibRegs.SCIPRI.bit.FREE = 0;
ScibRegs.SCICTL1.bit.SWRESET = 1;
}
void InitScibGpio(void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO22 = 0; // Enable pull-up for GPIO22 (SCITXDB)
GpioCtrlRegs.GPAPUD.bit.GPIO23 = 0; // Enable pull-up for GPIO23 (SCIRXDB)
GpioCtrlRegs.GPAQSEL2.bit.GPIO23 = 3; // Asynch qual for GPIO23 (SCIRXDB)
GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 3; // Configure GPIO22 for SCITXDB operation
GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 3; // Configure GPIO23 for SCIRXDB operation
EDIS;
}
复位函数:
void SciReset(Uchar dev)
{
volatile struct SCI_REGS *p;
switch(dev)
{
case Sci_a:
p = &SciaRegs;
break;
case Sci_b:
p = &ScibRegs;
break;
default:
p = &SciaRegs;
break;
}
if( p->SCIRXST.bit.RXERROR || p->SCIRXST.bit.FE ||
p->SCIRXST.bit.PE || p->SCIRXST.bit.OE )
{
p->SCICTL1.bit.SWRESET = 0;
DELAY_US(100);
p->SCICTL1.bit.SWRESET = 1;
}
}
写函数:
Uint16 WriteSci(Uchar dev,char *buf,Uint16 cnt)
{
static Uint16 i,Num;
volatile struct SCI_REGS *p;
switch(dev)
{
case Sci_a:
p = &SciaRegs;
break;
case Sci_b:
p = &ScibRegs;
break;
default:
p = &SciaRegs;
break;
}
i=0;
Num = cnt;
SciReset_C1062(dev);
while(p->SCIFFTX.bit.TXFFST != 0);
p->SCICTL1.bit.TXWAKE = 1;
p->SCITXBUF = 0xAA;
while(i < Num)
{
while(p->SCIFFTX.bit.TXFFST >= 4);
p->SCITXBUF = buf[i++];
}
return(i);
}
读函数:
读函数这里有个DELAY_US(3800),这个非常重要,没有这个延时RS485没法正常的读取数据,至于原理,暂时我也没完全搞清楚,应该是为了度过发送数据的而产生的低电平吧,因为DIR引脚为高时,ADM2587EBRWZ芯片的引脚会把SCI的Rx引脚拉低,如果这段时间SCIRX引脚读数据会读到错误的数据,因为SCI的Rx引脚读取数据时,认为8个时钟周期的低电平就是一个有效的数据起始位,这个读函数完全时为了RS485而准备的,我也试过RS232,当使用RS232时,SCI的收发是互不干扰,就没有这个问题。
Uint16 ReadSci(Uchar dev,char *buf)
{
static Uint16 i;
volatile struct SCI_REGS *p;
switch(dev)
{
case Sci_a:
p = &SciaRegs;
break;
case Sci_b:
p = &ScibRegs;
break;
default:
p = &SciaRegs;
break;
}
SciReset_C1062(dev);
if(p->SCIFFRX.bit.RXFFST == 0)
{
return(0);
}
i = 0;
do
{
while(p->SCIFFRX.bit.RXFFST != 0)
{
buf[i] = p->SCIRXBUF.bit.RXDT;
i ++;
}
DELAY_US(3800);
}while(p->SCIFFRX.bit.RXFFST != 0);
return(i);
}
忙函数:
void BusyWaitingSci(Uchar dev)
{
volatile struct SCI_REGS *p;
switch(dev)
{
case Sci_a:
p = &SciaRegs;
break;
case Sci_b:
p = &ScibRegs;
break;
default:
p = &SciaRegs;
break;
}
while(p->SCIFFTX.bit.TXFFST > 0);
}
波特率设置函数:
void SetBaudrateSci(Uchar dev,Uint32 baud)
{
Uint32 rate;
volatile struct SCI_REGS *p;
switch(dev)
{
case Sci_a:
p = &SciaRegs;
break;
case Sci_b:
p = &ScibRegs;
break;
default:
p = &SciaRegs;
break;
}
rate = 20000000 / (baud*8) - 1;
p->SCIHBAUD = rate >> 8; //20M baud 9600 2603
p->SCILBAUD = rate & 0x0FF;
}
写函数:
void Rs485Write(char *buf,Uint32 Baudrate,Uint16 cnt)
{
float ByteDelay;
ByteDelay = (1000000 / Baudrate ) * 11;
RcvDisable();
DELAY_US(10);
ADM2587_Write(buf,cnt);
ADM2587_BusyWaiting();
DELAY_US(ByteDelay);
RcvEnable();
}
读函数:
Uint16 Rs485Read(char *buf)
{
RcvEnable();
DELAY_US(10);
return(ADM2587_Read(buf));
}
头文件:
#define ADM2587_Write(buf,cnt) WriteSci(Sci_b,buf,cnt)
#define ADM2587_Read(buf) ReadSci(Sci_b,buf)
#define ADM2587_BusyWaiting() BusyWaitingSci(Sci_b)
#define ADM2587_BaudrateSet(baud) SetBaudrateSci(Sci_b,baud)
#define RcvDisable() GpioDataRegs.GPBSET.bit.GPIO50 = 1
#define RcvEnable() GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1