K60学习笔记五:串行通信的时序分析

串行通信的特点:数据以字节为单位,按位的优先级来进行传送
通信涉及通信协议
通信协议按照时间来分:可分为同步通信和异步通信
按照发送数据的位宽来分可分为:串行通信和并行通信
串行通信又分为单工,半双工,全双工
同步通信是面向比特的传输
异步通信是面向字符的传输,需要事先约定波特率
异步通信的空闲格式为1,发送器通过0来表示传送开始,随后传送数据位,再然后发送一到两位的停止位,来停止。
从开始位到停止位称为一帧。
因为没发送一个数据都要发送一个开始位,所以称为异步

串行通信的波特率:
位长:称为位的持续时间,其倒数就是单位时间内传递的位数。人们把每秒传送的位数称为波特率

看了一下数据手册UART 的配置寄存器好多
看了一下书:
UART寄存器初始化步骤:
使能UART时钟
设置UART的服用引脚
先禁止UART发送和接收,以便后续配置UART
设置UART的数据格式,奇偶校验位–停止位数固定为1
设置UART的波特率
如果需要FIFO,还要使能FIFO
使能UART发送和接收
—配置过程好复杂··
PLL锁相环,可以将晶振输出频率Fosc,倍增几倍,以满足高速运算需要。 在不连接PLL时,CPU时钟和晶振时钟相同,即CCLK = Fosc。 当使能PLL并连接,则CCLK = Fosc * M,M为倍频数。
锁相环和锁频环的锁定以及捕获、同步等概念是有区别的。对锁相环而言,所谓锁定是指VCO频率与同步信号频率完全一致,但允许有稳定相位误差;而对锁频环而言,则在锁定时可允许VCO与同步信号有小的稳态频率误差。

关于晶振:
时钟电路
MK60 的时钟电路包括两部分,一个是芯片的主晶振,用于产生芯片和外设所需要的工作时钟;另外一个是实时时钟RTC 的时钟电路,实时时钟(RTC-Real Time Clock)提供一套计数器在系统上电和关闭操作时对时间进行测量,RTC 消耗的功率非常低。蓝
宙电子的K60 系统板的主晶振使用的是50MHz 的有源晶振。
K60 的RTC 时钟由独立的32.768KHz 振荡器来提供。

void uart_init (UARTn_e uratn, uint32 baud)
{
    register uint16 sbr, osr;
    uint8 temp;
    uint32 sysclk,tmp_baud;     //时钟
    uint16 tmp_diff=~0,tmp_sbr,diff_abs_baud;

    /* 配置 UART功能的 复用管脚 */
    switch(uratn)
    {
    case UART0:
        SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;      //使能 UART0 时钟

        if(UART0_RX_PIN == PTA1)
        {
            port_init( UART0_RX_PIN, ALT2);
        }
        else if((UART0_RX_PIN == PTA15)  || (UART0_RX_PIN == PTB16) || (UART0_RX_PIN == PTD6) )
        {
            port_init( UART0_RX_PIN, ALT3);
        }
        else
        {
            ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
        }

        if(UART0_TX_PIN == PTA2)
        {
            port_init( UART0_TX_PIN, ALT2);
        }
        else if((UART0_TX_PIN == PTA14)  || (UART0_TX_PIN == PTB17) || (UART0_TX_PIN == PTD7) )
        {
            port_init( UART0_TX_PIN, ALT3);
        }
        else
        {
            ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
        }

        break;

    case UART1:
        SIM_SCGC4 |= SIM_SCGC4_UART1_MASK;

        if((UART1_RX_PIN == PTA18) || (UART1_RX_PIN == PTC3) || (UART1_RX_PIN == PTE1) )
        {
            port_init( UART1_RX_PIN, ALT3);
        }
        else
        {
            ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
        }

        if((UART1_TX_PIN == PTA19)  || (UART1_TX_PIN == PTC4) || (UART1_TX_PIN == PTE0) )
        {
            port_init( UART1_TX_PIN, ALT3);
        }
        else
        {
            ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
        }

        break;

    case UART2:
        SIM_SCGC4 |= SIM_SCGC4_UART2_MASK;

        if((UART2_RX_PIN == PTD2) || (UART2_RX_PIN == PTD4) || (UART2_RX_PIN == PTE17))
        {
            port_init( UART2_RX_PIN, ALT3);
        }
        else if(UART2_RX_PIN == PTE23)
        {
            port_init( UART2_RX_PIN, ALT4);
        }
        else
        {
            ASSERT(0);                           //上诉条件都不满足,直接断言失败了,设置管脚有误?
        }

        if((UART2_TX_PIN == PTD3) || (UART2_TX_PIN == PTD5) || (UART2_TX_PIN == PTE16))
        {
            port_init( UART2_TX_PIN, ALT3);
        }
        else if(UART2_TX_PIN == PTE22)
        {
            port_init( UART2_TX_PIN, ALT4);
        }
        break;


    default:
        break;
    }

  //管脚复用完毕 


    if( uratn == UART0)
    {
        //选择 FLL 或者 PLL/2 (山外代码使用 PLL,因此为 PLL 的 1/2 )
        SIM_SOPT2 &= ~SIM_SOPT2_UART0SRC_MASK;  //

   // SIM_SOPT2 0100 0000 0000 0100 1000 0000 0000 0100
 // SIM_SOPT2_UART0SRC_MASK ~(0000 1100 0000 0000 0000 0000 0000 0000)
 // SIM_SOPT2_UART0SRC_MASK 1111 0011 1111 1111 1111 1111 1111 1111
   // SIM_SOPT2 0100 0000 0000 0100 1000 0000 0000 0100 

     // 0x40048000
        SIM_SOPT2 |= (0
                      | SIM_SOPT2_UART0SRC(1)       //
                      | SIM_SOPT2_PLLFLLSEL_MASK
                     );

          //以上为选择PLL时钟

        // 设置的时候,应该禁止发送接受
        UART0_C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);

        //0000 0000 0000 0000 0100 0000 0000 0110
                     //1000 0100 1100 -- 1100
        //0000 0000 0000 0000 0000 0000 0000 0100 
        UART0_C1 = 0;       //默认工作模式
        sysclk = pll_clk_mhz * 1000* 1000/2;

        //UART 波特率 = UART 模块时钟/((OSR+1) × SBR)
        //4 <= OSR <= 32
        //SBR = (1 ,8191)
        for(temp = 4;temp<=32;temp++)
        {
            tmp_sbr = sysclk/(baud*(temp+1));
            if(tmp_sbr > 0x1FFF)
            {
                continue;
            }
            tmp_baud = sysclk/(tmp_sbr*(temp+1));
            diff_abs_baud =  ABS((int32)(tmp_baud - baud));
            if(diff_abs_baud == 0)
            {
                sbr = tmp_sbr;
                osr = temp;
                break;
            }
            if(tmp_diff > diff_abs_baud )
            {
                tmp_diff = diff_abs_baud;
                sbr = tmp_sbr;
                osr = temp;
            }

            //由于不一定是整除,因此还需要 加1 试试
            tmp_sbr++;
            if(tmp_sbr > 0x1FFF)
            {
                continue;
            }
            tmp_baud = sysclk/(tmp_sbr*(temp+1));
            diff_abs_baud =  ABS((int32)(tmp_baud - baud));
            if(diff_abs_baud == 0)
            {
                sbr = tmp_sbr;
                osr = temp;
                break;
            }
            if(tmp_diff > diff_abs_baud )
            {

                sbr = tmp_sbr;
                osr = temp;
            }
        }

        //写 SBR
        temp = UART0_BDH & (~UART0_BDH_SBR_MASK);           //缓存 清空 SBR 的 UARTx_BDH的值
        UART0_BDH = temp |  UART0_BDH_SBR(sbr >> 8);        //先写入SBR高位
        UART0_BDL = UART0_BDL_SBR(sbr);                     //再写入SBR低位

        //写 OSR
        temp = UART0_C4 & (~UART0_C4_OSR_MASK) ;           //缓存 清空 BRFA 的 UARTx_C4 的值
        UART0_C4 = temp |  UART0_C4_OSR(osr);             //写入BRFA

        // 设置完毕后,应该使能发送接受
        UART0_C2 |= (UART0_C2_TE_MASK | UART0_C2_RE_MASK);
    }
    else
    {
        //设置的时候,应该禁止发送接受
        UART_C2_REG(UARTN[uratn]) &= ~(0
                                   | UART_C2_TE_MASK
                                   | UART_C2_RE_MASK
                                  );

        //配置成8位无校验模式
        //设置 UART 数据格式、校验方式和停止位位数。通过设置 UART 模块控制寄存器 C1 实现;
        UART_C1_REG(UARTN[uratn]) = (0
                                      //| UART_C2_M_MASK //9 位或 8 位模式选择 : 0 为 8位 ,1 为 9位(注释了表示0,即8位) (如果是9位,位8在UARTx_C3里)
                                      //| UART_C2_PE_MASK //奇偶校验使能(注释了表示禁用)
                                      //| UART_C2_PT_MASK //校验位类型 : 0 为 偶校验 ,1 为 奇校验
                                     );

        sysclk = bus_clk_khz * 1000;                                    //bus时钟

        //UART 波特率 = UART 模块时钟 / (16 × (SBR[12:0] ))
        //不考虑 BRFA 的情况下, SBR = UART 模块时钟 / (16 * UART 波特率)
        sbr = (uint16)(sysclk / (baud * 16));
        if(sbr > 0x1FFF)sbr = 0x1FFF;                                       //SBR 是 13bit,最大为 0x1FFF

        //写 SBR
        temp = UART_BDH_REG(UARTN[uratn]) & (~UART_BDH_SBR_MASK);           //缓存 清空 SBR 的 UARTx_BDH的值
        UART_BDH_REG(UARTN[uratn]) = temp |  UART_BDH_SBR(sbr >> 8);        //先写入SBR高位
        UART_BDL_REG(UARTN[uratn]) = UART_BDL_SBR(sbr);                     //再写入SBR低位

        /* 允许发送和接收 */
        UART_C2_REG(UARTN[uratn]) |= (0
                                      | UART_C2_TE_MASK                     //发送使能
                                      | UART_C2_RE_MASK                     //接收使能
                                      //| UART_C2_TIE_MASK //发送中断或DMA传输请求使能(注释了表示禁用)
                                      //| UART_C2_TCIE_MASK //发送完成中断使能(注释了表示禁用)
                                      //| UART_C2_RIE_MASK //接收满中断或DMA传输请求使能(注释了表示禁用)
                                     );
    }

    //设置是否允许接收和发送中断。通过设置 UART 模块的 C2 寄存器的
    //RIE 和 TIE 位实现。如果使能中断,必须首先实现中断服务程序;
}

//这个是关于UART的初始化的一些程序,涉及到的寄存器太多,有些逻辑运算太绕了···
其他的UART API程序基本一个样,就不一一列举了

你可能感兴趣的:(通信,数据,异步)