DSP开发:串口sci的发送与接收实现
文章目录
串口配置
/*--------------------------------------------scia----------------------------*/
/*--------------------------------------------串口1----------------------------*/
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
EDIS;
InitSciaGpio();
//Initalize the SCI FIFO
SciaRegs.SCIFFTX.all=0xE040;
SciaRegs.SCIFFRX.all=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
}
// Transmit a character from the SCI'
void UARTa_SendByte(int a)
{
while (SciaRegs.SCIFFTX.bit.TXFFST != 0);
SciaRegs.SCITXBUF=a;
}
void UARTa_SendString(char * msg)
{
int i=0;
while(msg[i] != '\0')
{
UARTa_SendByte(msg[i]);
i++;
}
}
char SCITXDA_TX_BUF[400];
void printf_SCITXDa(char *fmt, ...)
{
Uint16 i, j;
va_list ap;
va_start(ap, fmt);
vsprintf((char*) SCITXDA_TX_BUF, fmt, ap);
va_end(ap);
i = strlen((const char*) SCITXDA_TX_BUF); //此次发送数据的长度
for (j = 0; j < i; j++) //循环发送数据
{
while (SciaRegs.SCIFFTX.bit.TXFFST != 0)
;
SciaRegs.SCITXBUF = SCITXDA_TX_BUF[j];
}
}
/*
* @name fputc,fputs
* @brief 串口打印重定向
* @param None
* @retval None
*/
int fputc(int _c, register FILE *_fp)
{
UARTa_SendByte(_c);
return _c;
}
int putc(int _c, register FILE *_fp)
{
UARTa_SendByte(_c);
return _c;
}
int putchar(int data)
{
UARTa_SendByte(data);
return data;
}
int fputs(const char *_ptr, register FILE *_fp)
{
unsigned int i, len;
len = strlen(_ptr);
for (i = 0; i < len; i++)
{
UARTa_SendByte((char) _ptr[i]);
}
return len;
}
这段代码实现了串口SCI(串行通信接口)的初始化以及向串口发送数据的功能,并且通过函数重定向,将标准库的输出函数重定向到串口SCI上,实现了通过类似于标准库的 printf 函数的格式化字符串向串口SCI发送数据的功能。
以下是代码的详细解释:
UARTa_Init 函数:
这个函数用于初始化串口SCI通信。它接收一个参数 baud,表示所需的波特率。函数通过计算波特率分频寄存器的值来设置波特率。
UARTa_SendByte 函数:
这个函数用于将一个字符发送到串口SCI。它通过检查发送FIFO的状态位来判断是否可以发送数据,然后将字符 a 发送到SCI的发送缓冲区(SCITXBUF)中。
UARTa_SendString 函数:
这个函数用于将一个字符串发送到串口SCI。它通过循环逐个字符地将字符串中的字符发送到串口SCI。
printf_SCITXDa 函数:
这是一个自定义的输出函数。它采用了与标准库函数 printf 类似的格式,支持格式化字符串,通过变参列表处理不定数量的参数。
char *fmt, ...:第一个参数 fmt 是格式化字符串,后续参数使用 ... 表示不定数量的变参。
va_list ap:va_list 是C标准库中用于处理变参的类型。ap 是一个变参列表指针,用于访问传递给函数的变参。
标准库函数重定向:
代码中重定义了标准库中的 fputc、putc、putchar 和 fputs 函数,使它们调用 UARTa_SendByte 函数向串口SCI发送数据。
通过这些函数的重定向,程序可以使用类似于标准库的 printf 函数的格式化字符串,将数据输出到串口SCI。同时,fputc、putc、putchar 和 fputs 函数也能直接将数据输出到串口SCI,方便地进行调试和输出结果信息。需要注意的是,由于串口发送速率有限,如果发送数据过于频繁,可能会导致数据丢失或串口阻塞。因此,在实际使用中应该适度控制发送频率,确保数据发送的稳定性。
串口SCI初始化详细分析
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
EDIS;
InitSciaGpio();
//Initalize the SCI FIFO
SciaRegs.SCIFFTX.all=0xE040;
SciaRegs.SCIFFRX.all=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
}
这段代码是用于初始化串口SCI(串行通信接口)的函数 UARTa_Init,该函数用于配置SCI的寄存器和相关参数,以便实现指定的波特率和通信设置。让我们逐个分析设置的寄存器对应位的功能和效果:
unsigned char scihbaud=0;
unsigned char scilbaud=0;
Uint16 scibaud=0;
这里定义了用于保存波特率计算结果的变量 scihbaud 和 scilbaud 作为高8位和低8位,以及 scibaud 作为16位整数用于计算波特率分频寄存器的值。
scibaud=37500000/(8*baud)-1;
这行代码根据输入的波特率值 baud 计算波特率分频寄存器的值 scibaud。LSPCLK(低速外设时钟)的频率为 37.5MHz,SCI的分频因子为 8(由于设置了 SCIHBAUD 和 SCILBAUD 分别为高8位和低8位),所以分频后的SCI时钟频率为 37.5MHz / 8 = 4.6875MHz。因此,计算公式为:波特率分频值 = SCI时钟频率 / 波特率 - 1。
scihbaud=scibaud>>8;
scilbaud=scibaud&0xff;
这两行代码将计算得到的波特率分频寄存器的值 scibaud 分解成高8位和低8位,分别存储在 scihbaud 和 scilbaud 中。
EALLOW;
SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1; // SCI-A
EDIS;
这部分代码使能了SCI-A模块的时钟(PCLKCR0 寄存器的 SCIAENCLK 位设置为1),从而允许对SCI-A进行配置。
InitSciaGpio();
这是一个初始化SCI-A相关的GPIO(通用输入输出端口)的函数。通过这个函数,将相应的GPIO引脚设置为与SCI-A功能相匹配,从而实现SCI-A的通信。
SciaRegs.SCIFFTX.all=0xE040;
SciaRegs.SCIFFRX.all=0x204f;
SciaRegs.SCIFFCT.all=0x0;
这些代码用于配置SCI FIFO(First In, First Out)寄存器,用于配置SCI发送和接收的FIFO的触发阈值等参数。
SciaRegs.SCICCR.all =0x0007;
SciaRegs.SCICTL1.all =0x0003;
SciaRegs.SCICTL2.all =0x0003;
SciaRegs.SCICTL2.bit.TXINTENA =1;
SciaRegs.SCICTL2.bit.RXBKINTENA =1;
这些代码配置了SCI的控制寄存器(SCICCR)、控制寄存器1(SCICTL1)和控制寄存器2(SCICTL2)。其中的设置如下:
SCICCR.all = 0x0007:设置为 1 停止位,无环回,无奇偶校验,8 个字符位,异步模式,空闲线协议(idle-line protocol)。
SCICTL1.all = 0x0003:使能发送(TX)、接收(RX)和内部 SCICLK。同时,禁用接收错误、睡眠模式和发送唤醒。
SCICTL2.all = 0x0003:使能发送中断(TXINTENA)和接收中断(RXBKINTENA)。
SciaRegs.SCIHBAUD = scihbaud;
SciaRegs.SCILBAUD = scilbaud;
这里将之前计算得到的波特率分频寄存器值 scihbaud 和 scilbaud 分别设置到 SCI 模块的高位波特率寄存器(SCIHBAUD)和低位波特率寄存器(SCILBAUD),从而配置了SCI的波特率。
SciaRegs.SCICTL1.all = 0x0023;
最后,这行代码将 SCI 模块的控制寄存器1设置为 0x0023,从而解除 SCI 模块的复位状态,使得SCI模块开始工作。
通过上述配置,串口SCI(SCI-A)已经被成功初始化,并配置了指定的波特率和通信设置。接下来,可以通过串口SCI进行数据的发送和接收操作。
串口SCI使用
/*
* main.c
*
* Created on: 2023年7月9日
* Author: 黎
*/
#include "main.h"
#define MAX_STRING_LENGTH 100 // 定义字符串的最大长度
void main()
{
int i = 0;
char *msg;
Uint16 ReceivedChar = 0;
char scia_rx_buf[MAX_STRING_LENGTH] = { 0 };
int rx_flag = 1;
int StringIndex = 0; // 字符串索引
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
UARTa_Init(4800);
while (1)
{
printf("\r\nEnter a character: ");
while (rx_flag)
{
// Wait for inc character// 等待接收字符
while (SciaRegs.SCIFFRX.bit.RXFFST != 1)
; // wait for XRDY =1 for empty state// 等待 XRDY = 1,表示缓冲区非空
// Get character读取接收到的字符
ReceivedChar = SciaRegs.SCIRXBUF.all;
// 检查是否为换行符或字符串超过最大长度
if (ReceivedChar == '\n' || StringIndex >= MAX_STRING_LENGTH - 1)
{
scia_rx_buf[StringIndex] = '\0'; // 在字符串末尾添加空字符
rx_flag = 0;
break; // 结束接收字符串
}
// 存储接收到的字符
scia_rx_buf[StringIndex] = ReceivedChar;
StringIndex++;
}
// Echo character back
printf(" You sent: ");
printf("\n scia_rx_buf = %s\r\n",scia_rx_buf);
rx_flag = 1;
StringIndex = 0;
DELAY_US(1000);
}
}
这段代码是一个示例程序,主要功能是通过串口SCI(SCI-A)接收用户输入的字符,并将输入的字符显示回终端上。
以下是代码的详细解释:
#define MAX_STRING_LENGTH 100
这里定义了一个宏 MAX_STRING_LENGTH,用于指定字符串的最大长度。在这个示例中,最大长度被设置为100。
void main()
这是程序的主函数入口。
变量初始化:
int i = 0;:一个用于循环计数的变量。
char *msg;:未使用的指针变量。
Uint16 ReceivedChar = 0;:用于存储接收到的字符的变量,初始值为0。
char scia_rx_buf[MAX_STRING_LENGTH] = { 0 };:用于存储接收到的字符串的字符数组,初始值全部为0。
int rx_flag = 1;:用于控制接收字符的标志位,初始值为1表示正在接收字符。
int StringIndex = 0;:字符串索引,用于指示当前接收到的字符在 scia_rx_buf 数组中的位置。
初始化系统控制和中断控制寄存器。
初始化串口SCI(SCI-A):
UARTa_Init(4800);:这个函数用于初始化SCI-A通信,并设置波特率为4800。
进入主循环 while (1):
通过 printf 函数提示用户输入字符:"Enter a character: "。
等待接收字符,while (rx_flag) 表示一直等待接收字符,直到 rx_flag 变为0。
在接收到字符时,通过 SciaRegs.SCIFFRX.bit.RXFFST 检查SCI接收缓冲区是否有字符到达。
读取接收到的字符,并存储在 ReceivedChar 中。
判断接收的字符是否为换行符或字符串长度是否超过最大长度(MAX_STRING_LENGTH),如果是,则结束接收,并在字符串末尾添加空字符('\0'),同时将 rx_flag 置为0,退出接收字符的循环。
否则,将接收到的字符存储在 scia_rx_buf 数组中,并增加 StringIndex 值,指示下一个字符应该存储在数组的下一个位置。
回显接收到的字符:
通过 printf 函数显示 "You sent: "。
通过 printf 函数显示接收到的字符串 scia_rx_buf。
最后,将 rx_flag 和 StringIndex 重置为初始值,然后通过 DELAY_US 函数延迟一段时间(这里是1000微秒)。
循环会不断重复,用户可以在终端输入字符,程序会接收并显示回显字符,直到结束。
如果文章对您有所帮助,点赞支持,感谢!!!!