打印
[技术问答]

M0518串口电平问题求助: 通信经常性存在乱码

[复制链接]
1883|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Harvard|  楼主 | 2016-4-17 13:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Harvard 于 2016-4-17 13:44 编辑

     

目前应用M0518进行一个多串口数据采集装置的产品设计, 样机制作成功后, 现在做整体测试, 发现一个问题.

波特率为:9600bps,  8/n/1, TTL交叉互联通信.

产品中,有与GSM手机模块通信, 其串口电平是2.8V, 单片机是采用 3.3v供电 .目前的情况是, GSM模块发过来的信息,总有个别会存在误码, 疑似串口的电平不一致导致.  想请教有没有什么简单的方法,来实现电平的兼容.按照Datasheet所示, 2.8v 应该在3.3v的范围之内.


   当通过下列语句对MFP等设置后,是否还有必要对串口所在的引脚的GPIO模式进行设置, 希望大家指导.


//If the defines do not exist in your project, please refer to the related sys.h in the sys_h folder appended to the tool package.
SYS->ALT_MFP = 0x00000000;
SYS->ALT_MFP2 = 0x00000000;
SYS->ALT_MFP3 = 0x00000000;
SYS->ALT_MFP4 = SYS_ALT_MFP4_PA3_UART3_RXD | SYS_ALT_MFP4_PA2_UART3_TXD |
SYS_ALT_MFP4_PA1_UART5_RXD | SYS_ALT_MFP4_PA0_UART5_TXD;
SYS->GPA_MFP = SYS_GPA_MFP_PA3_UART3_RXD | SYS_GPA_MFP_PA2_UART3_TXD |
SYS_GPA_MFP_PA1_UART5_RXD | SYS_GPA_MFP_PA0_UART5_TXD;
SYS->GPB_MFP = SYS_GPB_MFP_PB5_UART1_TXD | SYS_GPB_MFP_PB4_UART1_RXD |
SYS_GPB_MFP_PB1_UART0_TXD | SYS_GPB_MFP_PB0_UART0_RXD;
SYS->GPC_MFP = SYS_GPC_MFP_PC7_UART4_RXD | SYS_GPC_MFP_PC6_UART4_TXD;
SYS->GPD_MFP = SYS_GPD_MFP_PD15_UART2_TXD | SYS_GPD_MFP_PD14_UART2_RXD;
SYS->GPF_MFP = SYS_GPF_MFP_PF7_ICE_DAT | SYS_GPF_MFP_PF6_ICE_CLK;

以上是nuvoton pinconfig工具产生的代码 ,使用感觉不错.  是否还不需要对串口所在引脚做GPIO设定呢.

/* PB口上串口0: txd rxd  GPIO模式处理 */
GPIO_SetMode(PB,BIT,GPIO_PMD_OUTPUT);

GPIO_SetMode(PB,BIT0,GPIO_PMD_QUASI);



沙发
Harvard|  楼主 | 2016-4-17 13:49 | 只看该作者
 


u16  _crc16_update0(u16 crc, u08 a)
{
        int i;
        crc ^= a;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = (crc >> 1);
        }
        return crc;
}

/*
** 串行口初始化
** baudrate取值为: 48 96 192
*/

void usart0_init(u16 baudrate)
{
        /* Unlock protected registers */
    SYS_UnlockReg();
   
         /* Reset UART0 module */
    SYS_ResetModule(UART0_RST);
               
        /* Enable UART clock */
     CLK_EnableModuleClock(UART0_MODULE);

        /*---------------------------------------------------------------------------------------------------------*/
        /* Init UART                                                                                               */
        /*---------------------------------------------------------------------------------------------------------*/

    /* 选择uart功能 */
    UART0->FUN_SEL = UART_FUNC_SEL_UART;

    /* Tx FIFO Reset & Rx FIFO Reset & FIFO Mode Enable */
        //_UART_FLUSH_FIFO(UART0,UART_FCR_TFR_Msk | UART_FCR_RFR_Msk);
    UART0->FCR |=UART_FCR_TFR_Msk | UART_FCR_RFR_Msk;

    /* 选择RX FIFO的阀值为1BYTE*/
     _UART_SET_RX_TRG_LEV(UART0,UART_FCR_RFITL_1BYTE);
     
    if( baudrate != 9600 && baudrate != 19200 && baudrate != 4800&&baudrate != 2400 ) baudrate  = 2400;//默认值

    /* Set 115200 baudrate according to 50MHz system clock */
  //UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__IRC22M, baudrate);
      UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HXT, baudrate);
   
    /* 设置串口的工作方式 */   
   _UART_SET_DATA_FORMAT(UART0, UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1);


        /* Lock protected registers */
    SYS_LockReg();


    /* Enable RDA\RLS\Time-out Interrupt  */
    UART_ENABLE_INT(UART0, (UART_IER_RDA_IEN_Msk ));
   
    /* 开串口中断 */
    NVIC_EnableIRQ(UART02_IRQn);

}
/*
*        通信辅助功能控制开关
*/

void usart0_dis_recv(void)
{
    _UART_DISABLE_INT(UART0,UART_IER_RDA_IEN_Msk);
    //_UART_RS485_SET_RXDISABLE(UART0);
    UART0->FCR |= UART_FCR_RX_DIS_Msk; /*  Disable RS485 RX*/
   
   
}
void usart0_en_recv (void)
{
    _UART_ENABLE_INT(UART0,UART_IER_RDA_IEN_Msk);
    //_UART_RS485_CLEAR_RXDISABLE(UART0);
    UART0->FCR &= ~ UART_FCR_RX_DIS_Msk;  /* Enable RS485 RX */
   
     UART0_SEND = 0;

    /* 因为无法关闭串口接收,只能重新清楚FIFO并且消除RDA_IF标志位*/
//        _UART_FLUSH_FIFO(UART0,UART_FCR_RFR_Msk);

}

/*超时定时器初始化及其开关控制*/
#define T3_TICK_MIN                1000000/(F_CPU/1024)
#define T3_TICK                        1000        //1ms
#define TIMER3_BGN_VAL          (255-T3_TICK/T3_TICK_MIN)

//static u08 CNT_t15=0;                        //1.5字符时间
//static u08 CNT_t35=0;                        //3.5字符时间
static u08 SYS_t3_cnt_frame=0;                //时间间隔计数器,用于1.5 和3.5字符时间判断
u08     SYS_t3_on = OFF ;     //用于1.5 3.5字符判断的软定时器 开关.


void timer3_on(void)
{
   
    SYS_t3_cnt_frame = 0 ;
    SYS_t3_on = ON;
}
void timer3_off(void)
{
    SYS_t3_on = OFF;
    /** 帧间隔控制 */
    SYS_t3_cnt_frame = 0;

}

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       Timer-3 IRQ
*
* @param       None
*
* [url=home.php?mod=space&uid=266161]@return[/url]      None
*
* [url=home.php?mod=space&uid=1543424]@Details[/url]     The TIMER2 default IRQ, declared in startup_M051Series.s.
*/
void TMR3_IRQHandler(void)
{
    /* Clear TIMER2 Timeout Interrupt Flag */
    _TIMER_CLEAR_CMP_INT_FLAG(TIMER3);   

    /* 如果定时器打开 */
    if( SYS_t3_on == ON )
   {
          SYS_t3_cnt_frame++;
         
          if ( SYS_t3_cnt_frame > T35)         //a frame was finished
          {
               usart0_dis_recv();          //禁止接收中断

               timer3_off ()          ;   //tunr off timer;

               SYS_t3_cnt_frame = 0 ;   //reset timer

               RxBufPtr--;                         //调整指针        

               fFrameDone    = OK;   //frame is completed
               
               LED_DTU = 1;
           }      
    }
    /* 定时器关,还未进行帧间隔判断 */
   else
   {
        SYS_t3_cnt_frame = 0;
   }
   
}



u08 RxBuf[MAX_BUF_LEN]={0,1,2,3,4};
u08 TxBuf[MAX_BUF_LEN];
u08 RxBufPtr         = RX_BUF_BGN_ADR;
u08 TxBufPtr         = TX_BUF_BGN_ADR1;
BOOL fIsRXING        = NO;          //is receiving now
BOOL fIsTXING        = NO;          //is transsending now
BOOL fRxBufFull        = NO;
BOOL fTxBufFull = NO;
BOOL fFrameDone = NO;                   //one frame finished
BOOL fFrameBad = NO;                   //frame was broken
u16  CRC                = 0xFFFF;           //CRC初始值       


/*接收中断*/
void UART02_IRQHandler( void )
{
    /* 1-定义临时变量获取中断标志   */
    uint32_t u32IntSts= UART0->ISR;
   
    /* 2- 判断是否是RDA中断        */
    // 2-1:串口0处理
     if( UART_GET_INT_FLAG(UART0,UART_ISR_RDA_INT_Msk) )
    {
        /* 通信指示灯处理 */
         LED_DTU = 0;
        
        /* 查询串口的RDA */
        while(_UART_IS_RX_READY(UART0))
        {
            /* Get the character from UART Buffer
            *   BSP接收数据
            */
            RxBuf[RxBufPtr] = UART_READ(UART0);
            
           /* 复位定时器  */
           SYS_t3_cnt_frame = 0 ;   

            /*new frame coming*/
            if( RxBufPtr == RX_BUF_BGN_ADR )//新的一帧开始
            {
                CRC = 0xffff        ;                    //准备crc计算,

                timer3_on();                    //开启定时器计时
            }

            /*with a frame and RxBuf is not full*/
            /*when we detect a frame was borken according to t15 ,
            * we keep on receiving in order to synchronize the frame  
            */
            else if
              ( RxBufPtr < MAX_BUF_LEN -1)
            {  
                if ( SYS_t3_cnt_frame > T15 && SYS_t3_cnt_frame < T35 )
                {
                     SYS_t3_cnt_frame = 0 ;   //reset timer
               
                     fFrameBad     = TRUE; //frame is broken
                }
            }

            /*RxBuf full */
            /*
            **
            */
            else if
            ( RxBufPtr >= MAX_BUF_LEN -1)
            {
                usart0_dis_recv()    ;                         //stop receving
            
                timer3_off ()            ;            //tunr off timer;

                fRxBufFull           = YES ;            //缓冲区已满
               
                fFrameBad     = TRUE;            //frame is broken
               
                RxBufPtr --;                             //指针保持不变,防止破坏其他数据区
            
                LED_DTU = 1;
            }
               
                CRC = _crc16_update0( CRC,RxBuf[RxBufPtr] );

                RxBufPtr++;                                                //adjust pointer
        }//end while
      

        
     }//end if
    // END 2-1:串口0处理
   
    // 2-1:串口2处理
     
     

}

/*查询发送*/
void usart0_send_byte( u08 txbyte )
{
     UART0_SEND = 1;
    _UART_SENDBYTE( UART0,txbyte );
    _UART_WAIT_TX_EMPTY( UART0 );
}

使用特权

评论回复
板凳
heisexingqisi| | 2016-4-17 21:43 | 只看该作者
只要能用就好,不知道电平问题是什么问题,你用示波器看看没,是电压达不到吗

使用特权

评论回复
地板
tcchiu1| | 2016-4-25 17:26 | 只看该作者
M0518的串口,每一组的FIFO大小,好像是不一样了。这一点你有注意到吗??

使用特权

评论回复
5
liuyu305| | 2016-4-25 17:50 | 只看该作者
我还遇到过串口能收不能发的问题。换个片子就好了。

使用特权

评论回复
6
secretuniverse| | 2016-4-25 21:26 | 只看该作者
你用示波器看看电平是否是稳定的

使用特权

评论回复
7
643757107| | 2016-4-25 22:16 | 只看该作者
记得搞个上拉电阻,防止外界干扰,另外速度一般控制在9600就行了,如果是晶振的震源,就要看晶振是否靠谱了,要不实际的波特率不对。

使用特权

评论回复
8
Harvard|  楼主 | 2016-4-26 23:02 | 只看该作者
谢谢指点. 经查 是GSM模块引起的干扰. 电源加强后,现象消失

使用特权

评论回复
9
huangcunxiake| | 2016-4-26 23:06 | 只看该作者
电源加强后,现象消失??什么意思,这是怎么干扰到串口的?是电压不稳定吗

使用特权

评论回复
10
734774645| | 2016-4-27 19:55 | 只看该作者
/*查询发送*/
void usart0_send_byte( u08 txbyte )
{
     UART0_SEND = 1;
    _UART_SENDBYTE( UART0,txbyte );
    _UART_WAIT_TX_EMPTY( UART0 );
}

使用特权

评论回复
11
Roderman_z| | 2016-4-27 21:07 | 只看该作者
你的出现的情况是死机还是不能正常接收呢?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

74

主题

1730

帖子

21

粉丝