查看: 2050|回复: 3

[原创] KLxx系列芯片的UART0实验

[复制链接]
  • TA的每日心情
    开心
    2019-2-14 16:49
  • 签到天数: 296 天

    连续签到: 1 天

    [LV.8]以坛为家I

    241

    主题

    2239

    帖子

    6

    金牌会员

    Rank: 6Rank: 6

    积分
    4473
    最后登录
    2020-4-14
    发表于 2016-2-14 10:44:28 | 显示全部楼层 |阅读模式
    本讨论仅针对MKLxxZ128xxx系列的芯片做的一些测试和实验,目的是为了弄明白Freescale——老外们[也许是国人在函数编程上的一些思路——因为函数的嵌套太多以致让人想完全弄明白则必须就是用这款芯片——这不是在设计和选芯时的好方法,有时会丢了大量的客户!!!]
    2.UART的函数
    MKL_uart.h的一段定义
    #define MKL_UART0 0
      
    #define UART_PARITY_EN  1
    #define UART_PARITY_DIS 0
      
    #define UART_PARITY_EVEN 0
    #define UART_PARITY_ODD  1
    #define UART_10BIT_LENGTH 10
    #define UART_9BIT_LENGTH 9
    #define UART_8BIT_LENGTH 8
    #define UART_1BIT_STOP 1
    #define UART_2BIT_STOP 2
      
    #define UART_POLLED 0
    #define UART_INTERRUPT 1
    #define UART_DMA 2
    #define UART_TX_ENABLE  1
    #define UART_TX_DISABLE 0
    #define UART_RX_ENABLE  1
    #define UART_RX_DISABLE 0
    #define UART0_DEFAULT_OPEN 1//是否允许传输 1/0
    #define UART0_IRQ_ENABLE   1//串口中断允许 1/0
    #define UART0_SEND_IRQ     0//1/0
    #define UART0_RECEIVE_IRQ  1//1
    #define UART_PARAM_DEBUG   0//是否进行参数检查
      
    #define UART_PARAM_PORTNUM(x)   (x > 3? 1 : 0)//端口号检查
    #define UART_PARAM_MODE(x) (x > 3? 1 : 0)//模式检查
    #define UART_PARAM_LENGTH(x)    ((x == 8)||(x == 9)||(x == 9) ? 1 : 0)//数据长度检查
    #define UART_PARAM_STOP(x) ((x == 1)||(x == 2)? 1 : 0)//停止位检查
    #define UART_PARAM_PARITY(x)    ((x == 0)||(x == 1)? 1 : 0)//校验位检查
    #define UART_PARAM_LOGIC(x)((x == 0)||(x == 1)? 1 : 0)//逻辑位检查
    #define UART_CHECK_PARAM(x)(x? (while (1))//错误处理
    从函数定义和后边的注视来看十分清楚明了,Ok!很好操作!接着从MKL_urat0.c
    //uart0 Initial input parameters:
    //ucBaudRate:波特率;ucParityEnable:校验位选择;ucParityType:校验类型;ucDataLength:数据长度;ucStopBit:停止位;
    void  uart0Init(INT32U ulBaudRate,INT8U ucParityEnable,INT8U ucParityType,INT8U ucDataLength,INT8U ucStopBit){
    UART0_MemMapPtr uartPtr=UART0_BASE_PTR;
    register INT16U usBaudRate=0;
    #if UART_PARAM_DEBUG
    UART_CHECK_PARAM(UART_PARAM_LENGTH(ucDataLength));//由程序输入此4个数据
    UART_CHECK_PARAM(UART_PARAM_STOP(ucStopBit));
    UART_CHECK_PARAM(UART_PARAM_LOGIC(ucParityEnable));
    UART_CHECK_PARAM(UART_PARAM_PARITY(ucParityType));
    #endif
    SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
    SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1);//选择PLL时钟   
    SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;//允许外设时钟
    uart0TranControl(UART_TX_DISABLE, UART_RX_DISABLE);//首先禁止通信
    #if 1
    PORTA_PCR1 = PORT_PCR_MUX(0x2);//UART0_TXD ||默认首选输出I/O口
    PORTA_PCR2 = PORT_PCR_MUX(0x2);//UART0_RXD ||默认首选输入I/O口
    #endif
    #if 0
    PORTA_PCR14 = PORT_PCR_MUX(0x3);//UART0_TXD
    PORTA_PCR15 = PORT_PCR_MUX(0x3);//UART0_RXD
    #endif
    #if 0
    PORTD_PCR7 = PORT_PCR_MUX(0x3);//UART0_TXD
    PORTD_PCR6 = PORT_PCR_MUX(0x3);//UART0_RXD
    #endif
    #if 0
    PORTE_PCR20 = PORT_PCR_MUX(0x4);//UART0_TXD
    PORTE_PCR21 = PORT_PCR_MUX(0x4);//UART0_RXD
    #endif
    #if 0
    PORTE_PCR17 = PORT_PCR_MUX(0x3);//UART0_TXD
    PORTE_PCR16 = PORT_PCR_MUX(0x3);//UART0_RXD
    #endif                 //数据长度          //校验位类型     //校验位
    UART0_C1_REG(uartPtr) &= ~(UART0_C1_M_MASK|UART0_C1_PT_MASK|UART0_C1_PE_MASK);
    UART0_C4_REG(uartPtr) &= ~UART0_C4_M10_MASK;
    if(ucDataLength==10){
      UART0_C1_REG(uartPtr) |=(ucParityEnable << UART0_C1_PE_SHIFT)|(ucParityType << UART0_C1_PT_SHIFT);   
      UART0_C4_REG(uartPtr) |=UART0_C4_M10_MASK;   
    }else{
      UART0_C1_REG(uartPtr) |=((ucDataLength-8UL)<<UART0_C1_M_SHIFT)|(ucParityEnable<<UART0_C1_PE_SHIFT)|(ucParityType<<UART0_C1_PT_SHIFT);
    }
    usBaudRate = SystemBusClock/(ulBaudRate * 16);
    UART0_BDH_REG(uartPtr)  = (usBaudRate & 0x1F00) >> 8;//波特率
    UART0_BDL_REG(uartPtr)  = (INT8U)(usBaudRate & UART0_BDL_SBR_MASK);
    UART0_BDH_REG(uartPtr) &= ~UART0_BDH_SBNS_MASK;//停止位
    UART0_BDH_REG(uartPtr) |= (ucStopBit - 1) << UART0_BDH_SBNS_SHIFT;
    UART0_C2_REG(uartPtr)  &= ~(UART0_C2_TIE_MASK|UART0_C2_TCIE_MASK|UART0_C2_RIE_MASK|UART0_C2_ILIE_MASK);//清除中断设置
    while((UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK) && (UART0_D_REG(uartPtr)));//清接收缓冲区
    #if UART0_DEFAULT_OPEN   
    uart0TranControl(UART_TX_ENABLE, UART_RX_ENABLE);//配置完成允许通信
    #endif
    #if UART0_IRQ_ENABLE
    #if UART0_SEND_IRQ
    UART0_C2_REG(uartPtr) |= UART0_C2_TCIE_MASK;
    #endif
    #if UART0_RECEIVE_IRQ
    UART0_C2_REG(uartPtr) |= UART0_C2_RIE_MASK;
    #endif
    NVIC_EnableIRQ(UART0_IRQn);
    NVIC_SetPriority(UART0_IRQn,3);//用户自己定义
    #endif/**/
    }
    从此节的函数可以明了,UART0初始化函数,但从最后10行就不明白了:
    #if UART0_IRQ_ENABLE——如果UART0中断允许...
    #if UART0_SEND_IRQ——如果传输中断允许...
    #if UART0_RECEIVE_IRQ——如果接收中断允许...
    这3条定义实在不能让人理解。中断是让人为操作和定义的,就是说需要一些中断产生的信息时开中断,当不需要中断时将中断关掉以防止影响主程序的运行,而此处是用来判断中断是否开通!——通常判断中断是否完成是为了保证读取的数据完整性,实在不明白。算了,接着看:
    //ucTxEnable:发送使能控制;ucRxEnable:接收使能控制
    void  uart0TranControl(INT8U ucTxEnable,INT8U ucRxEnable){
    UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
    #if UART_PARAM_DEBUG
    UART_CHECK_PARAM(UART_PARAM_LOGIC(ucTxEnable));
    UART_CHECK_PARAM(UART_PARAM_LOGIC(ucRxEnable));
    #endif   
    UART0_C2_REG(uartPtr) &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
    UART0_C2_REG(uartPtr) |= (ucTxEnable << UART0_C2_TE_SHIFT)|(ucRxEnable << UART0_C2_RE_SHIFT);
    }
    这段很明确,是UART0传输和接收控制程序,按照前边函数定义0是禁止,1是允许,设置就Ok了。再接着:
    //uart0 Get Charact UART获取一个字节
    INT8U uart0GetChar(void){
    UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
    while (!(UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK));//等待接收缓冲区可用
    return UART0_D_REG(uartPtr);//返回接收字节
    }
    从UART0获取1个数据,返回的就是1个字节的数据,无问题,与上边的注释一致。再接着
    //uart0 Send a Charact UART发送一个字节 ucData:待发送字节
    void  uart0SendChar(INT8U ucData){
    UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
    while (!((UART0_S1_REG(uartPtr) & UART0_S1_TDRE_MASK)));//等待FIFO可用
    UART0_D_REG(uartPtr) = ucData;//填充数据寄存器
    }
    发送一个字节,好像没有问题,但实际上是有问题的!一会儿再说这个问题
    最后[跳过了连续发送存储区的一段]一段:
    //UART0_IRQHandler UART0中断服务函数
    void UART0_IRQHandler(void){  
    UART0_MemMapPtr uartPtr = UART0_BASE_PTR;//发送中断处理程序
    #if UART0_SEND_IRQ
    //while(!UART0_D_REG(uartPtr));//自加的!!!//发送中断处理程序|用户定义
    #endif
    #if UART0_RECEIVE_IRQ
    while(UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK){//清除中断标志UART0_S1_RDRF_MASK=0x20u
      uart0SendChar(UART0_D_REG(uartPtr));//返回接收数据
      //while(!UART0_D_REG(uartPtr));//清接收缓冲区 ||禁止!!!
    }   
    #endif
    }
    啊,中断服务函数,前半部分说明用户写的发送用户的程序,怎么写呢?尝试了各种写法都不成功,主要原因是此处属于定义函数,在主程序中定义的变量无法在此处调用,此节定义的又无法返回到主程序,这里能有什么用呢?不清楚
    第二段的uart0SendChar(UART0_D_REG(uartPtr));,如果此条开通,则接受的数据自动从TX口发送出去——就是透传了。如果注释掉此句,那么由
    uart0GetChar()得到的数据,无法用uart0SendChar()从TX口发送:程序段如下:
    temp=uart0GetChar();
    uart0SendChar(temp);
    你会发现程序毫无反应,就像对空操作一样。但如果你不注释掉uart0SendChar(UART0_D_REG(uartPtr));此句,前边的那个接收和发送就Ok!先别着急认为完了。你认为是接收了一个发送一个,还是接受几个发送几个?我做测试方法如下:
    主程序循环执行:
    temp=uart0GetChar();
    uart0SendChar(temp);
    LCD显示刷新屏幕
    串口调试助手接上UART0_RX和UART_TX,测试如下:
    A. 发送端输入1,结果有时发送1个1就有回应——显示屏循环刷新1次;有时需要输入两个1——显示器循环刷新1次;最多见的是输入3个1循环显示1次;好了我这样做实验:1次1个1、1次12、1次123——分别是1次输入1个、2个、3个字符,看程序如何响应,结果:
    1个的,响应最少、2个的响应次之、当连续输入3个字符后,几乎每次都响应——即程序能走到连续循环刷新屏幕。
    由此得出,此程序并不是1次读取1个字符和输出1个字符,从几率来说,3个字符的读取能保证中断执行1次!!!
    这样的程序有用吗?在无序乱读数据中是有用——产生随机数有用,但在需要读取的数据过程中要么多读丢数据,要么少读也丢数据!!!
    B. 改程序为:
    temp=UART0_D;//uart0GetChar();
    //uart0SendChar(temp);
    LCD显示刷新屏幕
    结果为无论第二句有无,程序都自动循环,说明可以实现自动收转发
    C. 如果改成:
    temp=UART0_D;//uart0GetChar();
    //uart0SendChar(temp);
    printf("\n\r"+temp);
    LCD显示刷新屏幕
    则在PC串口模拟器上输出的数据有变化,有时1换行23,有时123换行,有时123123才换行。并且程序受PC端TX触发影响?什么影响。
    总结:
    案例中的UART0程序几乎没有什么参考价值。充其量仅仅说明KL系列芯片有UART功能。
    本人觉得案例是应该简洁明了,并且针对实验者具有将来编程的指导意义。否则就属于误导。
    有人会说,那只是案例,你可以自己修改函数甚至会说自己去编函数!?是那样的话,人人都是编函数的天才了,走到这里的首先是初学者,可以说多数是从校门走来的,可能看都困难别说改和编写了。
    仅仅希望这些编引导应用的的函数或程序能精简点, 能做到简而明了,有可以自己加点什么就能扩充功能或改变应用的可能。可爱的Freescale,在BSP的函数上不妨学学Nutoton的BSP,他们的可操作性极强,注释清楚,增加改变功能比较容易。也许,从芯片的功能来说,F有着先天优势,N后发在追,如果总是固步自封,会让人追上的。
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2016-11-17 14:28
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    15

    主题

    296

    帖子

    0

    高级会员

    Rank: 4

    积分
    945
    最后登录
    2017-3-15
    发表于 2016-2-15 07:32:49 | 显示全部楼层
    是这样......

    UART2更加不是一般的麻烦


    https://item.taobao.com/item.htm?id=525890992684
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-5-3 11:19
  • 签到天数: 10 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    50

    主题

    1万

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    14090
    最后登录
    2024-4-19
    发表于 2016-2-15 09:47:45 | 显示全部楼层
    这排版,让人着急。。 blank.png blank1.png blank2.png blank3.png blank4.png blank5.png blank6.png blank7.png blank8.png blank9.png
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    4

    主题

    239

    帖子

    0

    高级会员

    Rank: 4

    积分
    673
    最后登录
    2018-6-8
    发表于 2016-2-15 10:04:11 | 显示全部楼层
    顶,赞,同感
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-22 20:18 , Processed in 0.088972 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表