串口通信_MSP430串口通信(入门级)

MSP430F5529实现双板间串口通信

62b46e505aff0deb0a2ff2cdb3ac2e11.png

年轻人,不要一上来就急着敲代码,串口通信用到的的13个寄存器,快来看看你都会了吗?

4caa69f3dadd23b9f054d006e6adef28.png

    哈哈哈~~,可千万不要被这些牛鬼蛇神吓住啊,这次我们讲的是入门级的,不会设置这么多寄存器的(但也不少呦)。

    准备好了吗?下面我们开讲了!

1.数据格式

7a8d34d30e20370f669677a3d3c02cc0.png

(1)ST:起始位(低电平启动串口)

因为串口待机时处于长期高电平状态,当检测到有低电平时,就会启动准备接收数据。

(2)D0~D7:数据位(可以7位,也可以8位)

1对应高定平,0对应低电平(这应该都清楚吧)

(3)AD:地址位:(双板通信用不到)

当多机通信时(例如一个设备发送,多个设备接收)

需要添加地址位,这样每个设备只需要接收自己对应地址的数据就行,避免了错误通信。

(4)PA:奇偶校验位

信号传输过程中可能(几率很小)会出错,发送前统计数据位1的个数是奇数还是偶数,接收是再次确认奇偶。

(5)SP:停止位(可以1位,也可以2位)

读到SP的高电平就意味着整段的数据接收完成了

看完了串口通信的数据格式,是不是觉得很简单呢?本来也不难嘛~ ~

2.工作结构

187ba04bbbec8f96787b770625223f65.png

这张图是我自己画的,为了助于理解做了相应简化

    1) 首先,我们都知道单片机内部读写数据都是并行操作,将并行的数据变为串行,自然就会想到用移位寄存器啦。

    2) 如果大家还记得数电里移位寄存器的波特图的话,肯定还记得CLK是个啥吧。什么是波特率?波特率就是字节传输的速率(单位时间内字节传输个数),接收端和发送端必须保证相同的波特率才能保证正确的通信。

    3) 那么缓冲寄存器又是个啥子呢?我们都知道数据的串行传输要比并行传输慢很多,如果移位寄存器还没有将旧数据移位完就添加新数据,势必会造成干扰,所以我们需要一个缓冲寄存器来暂时存储,等旧数据移位完成自动导入新数据。

    至于怎样向缓冲寄存器内读写数据,直接赋值不就ok了啦。

841800f6cd8bd4ee41e13833daefa7da.png

※3.操作流程(入门级)

流程概述:

    1)串口初始化

                    <1>TX/RX引脚功能复用

                    <2>串口控制寄存器配置

                    <3>设置波特率

                    <4>串口使能清除

                    <5>开启串口中断

   2)中断服务程序

具体操作:

串口初始化

 1.TX/RX引脚功能复用:

P4SEL |=BIT4+BIT5;//引脚功能复用

    msp430f5529有两个串口,UART0(P3^3、P3^4)和UART1(P4^4、P4^5),我们下面都以UART1为例进行介绍。

2.UART控制寄存器的介绍:

ab07494c1e6a302772b9c924ce1416ed.png

<1>UCPEN:奇偶使能 

0/1 奇偶禁止/奇偶使能(奇偶位的产生和接受);

<2>UCPAR奇偶选择

 0/1 奇校验 / 偶校验;

<3>UCMSB 控制接收和发送移位寄存器的方向 

0/1 LSB先 / MSB先;

<4>UC7BIT 数据位长度 

0/1 8位数据 / 7位数据;

<5>UCSPB 停止位个数

0/1 一个停止位 / 两个停止位;

<6>UCMODEx  USCI模式 

00/01/02/03  USART / 空闲线多机 / 地址位多机 / UART自动波特率检测模式;

<7>UCSYNC  

0/1 异步模式 / 同步模式;

0af54078a99f2db97fff7735feaef93a.png

<1>UCSSELx 选择BRCLK时钟源

 00/01/10/11: UCLK / ACLK / SMCLK / MCLK;

<2>UCRXEIE 接收错误字符中断使能 

0/1 :错误字符丢弃 / 错误字符接收,

<3>UCBRKIE 接收暂停字符中断允许 

0/1 接收暂停字符不置位UCA0RXIFG / 接收暂停字符置位UCA0RXIG;

<4>UCDORM 睡眠态

 0/1 非睡眠态所有接收字符将置位UCA0RXIFG / 睡眠态,只有先于空闲态的带地址字符将置位UCA0RXIFG;

<5>UCTXADDR 发送地址标记地址

 0/1 下一帧是数据 / 下一帧是地址;

<6>UCTXBRK 发送暂停

(对将要写到发送缓存的数据带暂停)

 0/1 :发送下一帧不是暂停 / 是暂停;

<7>UCSWRST 软件复位使能

 0/1 禁止(USCI复位释放)/ 使能(复位状态保持);

        上面的控制位你随意配置,当然我们如果对数据的格式不是特别苛刻的话,只需要对几个必须的控制位进行配置,其他选择默认即可。默认就是控制位的值为零。

(例:UCPEN:奇偶使能,我没有设置默认,即默认UCA1CTL &= ~UCPEN,意味着奇偶使能的禁止)

        UCA1CTL1 |= UCSWRST ;//必须要有欧

3.波特率的配置:

    拿9600来举一个栗子吧

1)首先需要选择合适的时钟源

(我建议9600以下选择ACLK,以上选SMCLK)

        我的ACLK(辅助时钟信号)选的是外部低频晶体振荡器 f = 32.768kHZ

UCA1CTL1 |= UCSSEL_1;//ACLK

(这是前面控制寄存器的内容)

2)波特率需要配置三个寄存器,分别是

UCA1BR0: USCI_A1波特率寄存器0 (存整数的低八位)

UCA1BR1: USCI_A1波特率寄存器1(存整数的高八位)

UCA1MCTL: USCI_A1调制控制寄存器(存小数部分)

UCOS16: UCAxMCTL的一个控制位(0/1:低频/高频模式)

<1>低频模式

int【32.768k / 9600】=int【3.41】=3

UCOS16 默认为0,选择低频模式

UCA1BR0 = 0x03;//低八位

UCA1BR1 = 0x00;//高八位

round【(3.41—3)x 8】=round【3.28】= 3

(round是指取离它最近的整数)

UCA1MCTL |= UCBRS_3;

<2>高频模式

因为32.768k/9600 < 16 所以不能选择高频模式,为了更好地理解,我们假设我们的晶体振荡频率f = 1MHz

int【(1M/ 9600)/16】=int【6.51】=6

UCA1BR0 = 0x06;//低八位

UCA1BR1 = 0x00;//高八位

round【(6.51—6)x 16】=round【8.16】= 8

UCA1MCTL |= UCBRS_0+UCBRF_8+UCOS16;

4.串口使能清除

 UCA1CTL1 &= ~UCSWRST ;//必须要有欧

到此为止,串口初始化配置完成

5.开启中断

(1)串口中断(三选一欧)

UCA1IE |= UCTXIE;//开启发送中断

UCA1IE |= UCRXIE;//开启接收中断

UCA1IE |= UCRXIE + UCTXIE;//接收和发送中断都开启。

(2)全局中断

_EINT();//打开全局中断

620125f463cbc5290638d94f92e3047d.png

中断处理

    USCI通信接收中断和发送中断用的是同一个中断服务程序,所以我们需要在中断服务程序内部对中断类型进行判断,判断的方案有两种:标志位查询判断和中断向量值判断。

(1)标志位查询判断:

发送中断:

    如果发送缓冲寄存器UCAxTXBUF 已经准备好接收另一个字符,则UCTXIFG。如果 UCTXIE 和 GIE 也置位的话,将产生中断请求。

    如果将字符写入UCAxTXBUF,UCTXIFG 将自动复位。 PUC 之后或 UCSWRST = 1 时,UCTXIFG 置位。PUC 之后或 UCSWRST = 1 时,UCTXIE 复位。 

接收中断:(跟发送中断类似)

 接收到的数据载入到 UCA1RXBUF 时,UCRXIFG 中断标志置位。如果UCTXIE 和 GIE 也置位的话,将产生中断请求。

    UCRXIFG 和 UCRXIE 可以通过系统复位 PUC 信号或 UCSWRST = 1 复位。 当读取 UCA1RXBUF 时,UCRXIFG 自动复位。

代码如下:

 if (!(UCA1IFG&UCTXIFG))     // 判断是否是发送中断  

    {

        UCA1TXBUF = data;

    };

else if(!(UCA1IFG&UCRXIFG)) //判断是否是接收中断

    {

        data = UCA1RXBUF;

    };

else 

    break;

(2)中断向量值的判断

c00b77c548e3986cdf23b33ee9179733.png

switch(__even_in_range(UCA1IV,4))

{

  case 0:break;                            

  case 2:    

    {                              

        while (!(UCA1IFG&UCTXIFG));           

         UCA1TXBUF = data;

     }

  case 4:             

    {

         while (!(UCA1IFG&UCRXIFG));  

        data= UCA1RXBUF;

    }          

  default: break;

}

ps:__even_in_range(UCA1IV,4)在[0,4]区间内对UCA1IV进行遍历,提高了switch的效率

9bb5ad3bb098158ebe13827edcd8e5be.gif

最后附上代码(只贴一个板子的了,注释在教程里有)

#include  

void uart1_init();//串口初始化

int main(void)

{

    WDTCTL = WDTPW | WDTHOLD;// 关狗

uart1_init();

__bis_SR_register(LPM3_bits + GIE);       // 低功耗lpm3+全局中断

__no_operation();

}

void uart1_init()

{

P4SEL |=BIT4+BIT5;

 UCA1CTL1 |= UCSWRST;                     

UCA1CTL1 |= UCSSEL_1;                     // CLK = ACLK

UCA1BR0 = 0x03;                         

UCA1BR1 = 0x00;                           

 UCA1MCTL = UCBRS_3+UCBRF_0;              

UCA1CTL1 &= ~UCSWRST;                    

UCA1IE |= UCRXIE;       

return;                  

}

#pragma vector=USCI_A1_VECTOR

__interrupt void USCI_A1_ISR(void)

{

 switch(__even_in_range(UCA1IV,4))

{

  case 0:break;                            

  case 2:    

    {                              

        while (!(UCA1IFG&UCTXIFG));           

         UCA1TXBUF = data;

     }

  case 4:             

    {

         while (!(UCA1IFG&UCRXIFG));  

        data= UCA1RXBUF;

    }          

  default: break;

}

return;

}

ef4993a5638e71e847f765f38485be26.png

最后以我最喜欢的一句话结尾吧:

岁月悠悠,衰微只浸肌肤;热忱抛却,颓废必至灵魂。

不定期分享自动化专业知识

创作不易,跪求关注

  • 36
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值