DSP开发:串口sci的发送与接收实现

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微秒)。

循环会不断重复,用户可以在终端输入字符,程序会接收并显示回显字符,直到结束。

如果文章对您有所帮助,点赞支持,感谢!!!!

相关推荐
__基本操作__30 分钟前
历遍单片机下的IIC设备[ESP--0]
单片机·嵌入式硬件
网易独家音乐人Mike Zhou7 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
lantiandianzi14 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
哔哥哔特商务网14 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式14 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
东芝、铠侠总代1361006839316 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi16 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件
嵌入式知识大讲堂16 小时前
HDMI数据传输三种使用场景
单片机
黑客呀16 小时前
[系统安全]Rootkit基础
stm32·单片机·系统安全
楚灵魈17 小时前
[STM32]从零开始的STM32 HAL库环境搭建
stm32·单片机·嵌入式硬件