感芯多线程处理器MC3172评估板(四)- 串口的使用

感芯多线程处理器MC3172评估板(一)- 介绍与搭建开发环境 感芯多线程处理器MC3172评估板(二)- 点亮一个LED灯 感芯多线程处理器MC3172评估板(三)- 体验多线程同步并行

目录

前言

一、通用异步收发器(UART)

二、相关宏定义

 三、相关函数封装

四、编写程序

 五、硬件电路

 六、下载程序

 七、实验现象

 八、*注意事项

总结


前言

        上一篇文章通过编程实现两个IO口来感受多线程同步并行运行的效果,这一篇将通过编程串口的相关函数实现与电脑的通信。


一、通用异步收发器(UART)

        MC3172评估板可以配置12个串口,每四个IO一组,在组内串口的输入输出可以任意配置,非常灵活,和FPGA很相似。串口的基本知识不做介绍。

        本次串口选择第0组,选择线程组0,使用了板子上的48M无源晶振,串口波特率设为115200。若设为9600会溢出,115200的刚好,因此,选用115200。

二、相关宏定义

1.INTDEV_SET_CLK_RST(DEV_ADDR,value)

#define INTDEV_SET_CLK_RST(DEV_ADDR,value)      (*(volatile u32*)(DEV_ADDR))=(value)

        这个宏用于对外设进行启动,主要是设置外设使用的时钟频率以及特权组。使能了GPIOx对应的时钟。

        (1)DEV_ADDR是GPCOMx的外设,可以为GPCOM0_BASE_ADDRGPCOM2_BASE_ADDR、GPCOM3_BASE_ADDR、GPCOM4_BASE_ADDR、GPCOM5_BASE_ADDR.等等。

        (2)value参数:一般为(运行|线程组别|外设时钟分频设置)。

2. GPCOM_SET_IN_PORT(GPCOM_SEL,value)

#define GPCOM_SET_IN_PORT(GPCOM_SEL,value)         (*(volatile u32*)(GPCOM_SEL+GPCOM_IN_MODE_ADDR)) = value

        这个宏用于设置 输入管脚(可以在 P0-P3 按需设置)为接收引脚。

        (1)GPIO_SEL是GPCOMx的外设,可以为GPCOM0_BASE_ADDRGPCOM2_BASE_ADDR、GPCOM3_BASE_ADDR、GPCOM4_BASE_ADDR、GPCOM5_BASE_ADDR.等等。

        (2)value:是设置为输入引脚并设置为RXD引脚的引脚,可以为GPCOM_RXD_IS_P0或GPCOM_RXD_IS_P1或GPCOM_RXD_IS_P2或GPCOM_RXD_IS_P3。

3.GPCOM_SET_OUT_PORT(GPCOM_SEL,value)

#define GPCOM_SET_OUT_PORT(GPCOM_SEL,value)                 (*(volatile u32*)(GPCOM_SEL+GPCOM_OUT_MODE_ADDR)) = value

这个宏用于设置 输出管脚为发送引脚。

4.GPCOM_SET_COM_MODE(GPCOM_SEL,value)

#define GPCOM_SET_COM_MODE(GPCOM_SEL,value)                 (*(volatile u32*)(GPCOM_SEL+GPCOM_ITEM1_ADDR)) = value

 这个宏用于设置工作模式。

5.GPCOM_SET_COM_SPEED(GPCOM_SEL,clk_speed,baudrate)

#define GPCOM_SET_COM_SPEED(GPCOM_SEL,clk_speed,baudrate)   (*(volatile u32*)(GPCOM_SEL+GPCOM_ITEM2_ADDR)) = (((clk_speed/baudrate)-1)<<8)+(clk_speed/baudrate)/2-2

  这个宏用于设置串口工作频率和波特率,参数分别为GPCOM,外设时钟,串口波特率。

6.GPCOM_SET_OVERRIDE_GPIO(GPCOM_SEL,value) 

#define GPCOM_SET_OVERRIDE_GPIO(GPCOM_SEL,value)            (*(volatile u32*)(GPCOM_SEL+GPCOM_OVERRIDE_GPIO_ADDR)) = value

  这个宏用于设置串口管脚映射 GPIO。

7.GPCOM_GET_RX_WP(GPCOM_SEL)

#define GPCOM_GET_RX_WP(GPCOM_SEL)                          (*(volatile u8*)(GPCOM_SEL+GPCOM_RX_DATA_WP_ADDR))

  这个宏用于读取当前 RX 的缓存 FIFO 写指针。

8.GPCOM_GET_RX_DATA(GPCOM_SEL,rp) 

#define GPCOM_GET_RX_DATA(GPCOM_SEL,rp)                     (*(volatile u32*)(GPCOM_SEL+GPCOM_RX_DATA_BUF0_ADDR+(((rp&0x7)*8))))

  这个宏用于读取当前 RX 的缓存 FIFO 读指针 rp 指向的数据。

9.GPCOM_TX_FIFO_FULL(GPCOM_SEL)

#define GPCOM_TX_FIFO_FULL(GPCOM_SEL)            (((*(volatile u8*)(GPCOM_SEL+GPCOM_TX_DATA_RP_ADDR))^0x8)==(*(volatile u8*)(GPCOM_SEL+GPCOM_TX_DATA_WP_ADDR)))

  这个宏用于检查 TX 的发射缓存是否已满。

10.GPCOM_TX_FIFO_EMPTY(GPCOM_SEL)

#define GPCOM_TX_FIFO_EMPTY(GPCOM_SEL)           (((*(volatile u8*)(GPCOM_SEL+GPCOM_TX_DATA_RP_ADDR)))    ==(*(volatile u8*)(GPCOM_SEL+GPCOM_TX_DATA_WP_ADDR)))

  这个宏用于检查 TX 的发射缓存是否已空。

11.GPCOM_PUSH_TX_DATA(GPCOM_SEL,value)

#define GPCOM_PUSH_TX_DATA(GPCOM_SEL,value)                 (*(volatile u32*)(GPCOM_SEL+GPCOM_TX_DATA_BUF0_WPINC_ADDR+ (( (*(volatile u32*)(GPCOM_SEL+GPCOM_TX_DATA_WP_ADDR))*8 )&0x3f) )) = value

  这个宏用于把 value 送入 TX 发射缓存(TX 的发射缓存一共有 8 层,可以一次性送 8 个字节,非常高效)。

 三、相关函数封装

1.串口初始化函数

         MC3172评估板可以配置12个串口,为了方便初始化各个串口,将函数封装成如下。可通过修改函数的gpcom_sel参数来初始化相应的串口,该函数已默认将每组初始化串口的P2为RXD引脚,P3为TXD引脚。Thread_group为线程组,rate为串口波特率。

/*初始化UART0*/
void Uart_Init(u32 Thread_group,u32 gpcom_sel,u32 rate)
{
    /*启动外设*/
    //这个宏用于对外设进行启动共 12 个可选,具体位置见 MC3172 芯片手册,INTDEV_CLK_IS_CORECLK_DIV4:系统时钟分频
    INTDEV_SET_CLK_RST(gpcom_sel,(INTDEV_RUN|Thread_group|INTDEV_CLK_IS_CORECLK_DIV4));
    /*设置RXD引脚*/
    //这个宏用于设置 P2 为输入管脚(可以在 P0-P3 按需设置)P2为接收引脚
    GPCOM_SET_IN_PORT(gpcom_sel,(GPCOM_RXD_IS_P2));
    /*设置TXD引脚*/
    //这个宏用于设置 P3 为输出管脚(可以在 P0-P3 按需设置,P3为发送引脚
    GPCOM_SET_OUT_PORT(gpcom_sel,(\
            GPCOM_P0_OUTPUT_DISABLE|GPCOM_P1_OUTPUT_DISABLE|GPCOM_P2_OUTPUT_DISABLE|GPCOM_P3_OUTPUT_ENABLE|\
            GPCOM_P1_IS_HIGH       |GPCOM_P1_IS_HIGH       |GPCOM_P1_IS_HIGH       |GPCOM_P3_IS_TXD\
            ));
    /*设置工作模式*/
    GPCOM_SET_COM_MODE(gpcom_sel,GPCOM_UART_MODE);
    /*设置串口工作频率和波特率*/  
    GPCOM_SET_COM_SPEED(gpcom_sel,12000000,rate);//参数分别为GPCOM,外设时钟,串口波特率,
    /*映射引脚*/
    GPCOM_SET_OVERRIDE_GPIO(gpcom_sel,(\
            GPCOM_P2_OVERRIDE_GPIO|GPCOM_P2_INPUT_ENABLE|\
            GPCOM_P3_OVERRIDE_GPIO\
            ));
}

2.发送单个字节函数

/*发送单个byte*/
void Send_Byte(u32 gpcom_sel,u8 dat)
{
    while(GPCOM_TX_FIFO_FULL(gpcom_sel));//等待发送结束
    GPCOM_PUSH_TX_DATA(gpcom_sel,dat);//发送数据dat
}

 3.发送多个字节函数

/*发送多个字节*/
void Send_MultiByte(u32 gpcom_sel,u8 *dat)
{
    while(*dat!='\0')//判断是否结束
    {
        Send_Byte(gpcom_sel, *dat++);//发送字节
    }
}

4.接收处理函数

         接收到的数据储存在USART_RX_BUF里,可在行编写相关的处理内容。整体代码如下:

接收处理函数
void Rx_Data(u32 gpcom_sel)
{
    u8 rx_data_rp=0;
    u8 Res=0;
    rx_data_rp=GPCOM_GET_RX_WP(gpcom_sel);//读取当前 RX 的缓存 FIFO 写指针
    while(1) {
         if(rx_data_rp!=(GPCOM_GET_RX_WP(gpcom_sel))){
             Res=GPCOM_GET_RX_DATA(gpcom_sel,rx_data_rp);//读取当前 RX 的缓存 FIFO 读指针 rx_data_rp 指向的数据。
             if((USART_RX_STA&0x8000)==0)//接收未完成
              {
                  if(USART_RX_STA&0x4000)//接收到了0x0d
                  {
                      if(Res!=0x0a)USART_RX_STA=0;//接收状态标记
                      else //接收完成了
                      {
                        //添加串口接收到数据处理的内容
                        /*代码添加处*/
                        USART_RX_STA=0;//接收状态标记清零
                        memset(USART_RX_BUF,'\0',200);//清除缓存空间
                        rx_data_rp=GPCOM_GET_RX_WP(gpcom_sel);//读取当前 RX 的缓存 FIFO 写指针
                      }
                  }
                  else {//还没收到0X0D
                      if(Res==0x0d)USART_RX_STA|=0x4000;
                      else {
                          USART_RX_BUF[USART_RX_STA]=Res ;
                          USART_RX_STA++;
                          if(USART_RX_STA>(UART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
                    }
                    rx_data_rp++;
                    rx_data_rp&=0x0f;
                }
              }
         }
    }
}

四、编写程序

       (1) 在main.c文件中的void thread0_main(void)里编写代码程序如下:

void thread0_main(void)
{
    Uart_Init(INTDEV_IS_GROUP0,G_COM0,115200);
    Send_Byte(G_COM0,'H');
    Send_MultiByte(G_COM0,"ok\r\n");
    while(1){

    }
    thread_end();
}

     (2) 在Rx_Data()函数里添加代码如下,实现当接收数据第一个字符为A时,MC3172向电脑发送"Test2 A is ok\r\n",等等功能。

Send_MultiByte(gpcom_sel,USART_RX_BUF);
Send_MultiByte(gpcom_sel,"\r\n");
if(USART_RX_BUF[0]=='A')
{
    Send_MultiByte(gpcom_sel,"Test2 A is ok\r\n");
}
if(USART_RX_BUF[0]=='B')
    Send_MultiByte(gpcom_sel,"Test B is ok\r\n");
if(USART_RX_BUF[0]=='B'&&USART_RX_BUF[1]=='C')
    Send_MultiByte(gpcom_sel,"Test BC is ok\r\n");

      (3) 在main.c文件中的void thread4_main(void)里接收函数如下:

void thread4_main(void)
{
    while(1){
        Rx_Data(G_COM0);
    }
    thread_end();
}

 五、硬件电路

1.MC3172引脚图

参考《感芯MC3172手册_V1.03》里的 表 2-1 MC3172 LQFP100 引脚定义和IO排列顺序图

表 2-1 MC3172 LQFP100 引脚定义
IO排列顺序图

         同时也非常感谢一个网友的分享,将引脚定义的功能标准在IO排列顺序图里如下图,方便我们查看。

2. 引脚与USB转TTL模块的连接方式

        由上面的函数和手册可知,本次项目使用的COM0,PA2为RXD引脚,PA3为TXD引脚,因此将PA2接模块上的TXD引脚,PA3接RXD引脚。

 六、下载程序

        将MC3172评估板通过USB口接到电脑,然后打开Release文件夹下的开发板程序下载_v1.1.exe,这时就会识别出GX_LINK#0设备(也有可能是其它名字),点击连接设备,接着选择生成的*.hex固件,再点击烧录固件,最后等到进度条走到100%则下载成功。

 七、实验现象

        打开电脑串口调试助手,将其右侧的参数设置和代码中的一致,并打开串口。程序下载成功后,在串口显示区会输出“Hok”。点击多条发送窗口并输入相关的内容后,分别点击发送,对应串口显示区会显示评估板发送来的信息如下。

 八、*注意事项

        本次项目的波特率要根据实际计算,太低会超出,太高会不足,尽量满足100<(外设时钟/波特率)<200。我使用的是板子上的无源晶振48M,根据公式“外设时钟=系统时钟(48M)/时钟分频” 可计算出该外设的实际时钟频率为12000000。使用波特率为9600时超出,115200的不会,所以选择了115200。


总结

        以上就是对MC3172评估板串口学习过程记录分享,由于环境条件,本次项目只测试了一个串口,有条件的伙伴可以测试运行和体验一下多个串口的使用。如果文章中有误,有不足之处请大家多多关照并指出,谢谢!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值