MSP430系列教程之串口通信
串行接口是一种可以将接收来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。
在我们需要对采集到的数据进行处理时,常常会用到串口通信的方式与上位机通信
MSP430FR6989系列教程之流水灯
MSP430FR6989系列教程之串口通信
MSP430FR6989系列教程之定时器
MSP430FR6989系列教程之PWM波
MSP430FR6989系列教程之LCD
前言
这次学习MSP430主要是为了备战电赛,虽然不确信一定会用到MSP430FR6989这块板子,但还是想尝试一下,毕竟未来的事谁也说不准。
一、串口通信
通用异步收发器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种串行、异步、全双工的通信协议。
异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。不需要时钟线,两个设备上指定相同的传输速率,以及空闲位、起始位、校验位、结束位,也就是遵循相同的协议即可。
说的通俗点,就是收发双方约定好说话的频率,暗号,停顿和开始的标志,就像我们大家在说汉语交流的时候,你让一个河南人说着河南话去和一个说着粤语的广东人交流,显然是有些为难他们的,毕竟这两种语言具有着显著的地域特色,最后可能两人都无法理解对方在说什么,所以这时候就体现出一个统一的通信协议的重要性,如果你的上下位机在通信过程中遇到可以接收到数据,但数据都显示为乱码,可能是波特率设置的不一致的问题,这时你就需要来修改波特率,如果你需要与手机进行通信,建议你设置波特率为9600即可。
在MSP430FR6989用户指南UART篇782页的表格30-5,可以根据表格的参数来设置自己需要使用的串口波特率。
UCA1CTLW0 |= UCSSEL__SMCLK ; // 时钟=SMCLK 8M, 8 N 1 , LSB
UCA1BRW_L =04; // 115200bps,根据表中的UCBRx可得
UCA1BRW_H =00;
二、代码编写
这里附上完整的代码
#include <msp430.h>
#define CPU_CLOCK 8000000
#define Delay_Us(us) __delay_cycles(CPU_CLOCK / 1000000 * (us))
#define Delay_Ms(ms) __delay_cycles(CPU_CLOCK / 1000 * (ms))
/**
* uart.c
*/
unsigned short RxDataBuf[100];
unsigned short RxDataLen = 0;
unsigned short RxDataFlag = 0;
/*---------------------------------------*/
void Initial_Uart(void)
{
/* 串口引脚配置 P3.4/UCA1TXD P3.5/UCA1RXD */
P3DIR |= BIT4;
P3OUT |= BIT4;
P3SEL0 |= BIT4;
P3SEL1 &= ~BIT4;
P3DIR &= ~BIT5;
P3SEL0 |= BIT5;
P3SEL1 &= ~BIT5;
/* 使配置完成的IO口生效,从LPMx.5退出 */
PM5CTL0 &= ~LOCKLPM5;
/* 串口参数配置 */
UCA1CTLW0 = UCSWRST; // ----------------- 使能串口设置
UCA1CTLW0 |= UCSSEL__SMCLK ; // 时钟=SMCLK 8M, 8 N 1 , LSB
UCA1BRW_L =04; // 115200bps
UCA1BRW_H =00;
UCA1MCTLW_L = UCOS16 | UCBRF_5;
UCA1MCTLW_H = 0x55;
UCA1CTLW0 &= ~UCSWRST; // ----------------- 禁止串口设置
UCA1IE &= ~UCTXIE; // 禁止传输中断
UCA1IE |= UCRXIE; // 允许接受中断
}
void putByte(unsigned char Byte)
{
while (!(UCA1IFG&UCTXIFG)); // 等待标志位
UCA1TXBUF = Byte;
}
void printStr(char *pStr)
{
while ((*pStr != '\0'))
{
putByte(*pStr++);
}
return;
}
//putchar()会报错为重复定义,所以请不要取消注释
//int putchar(int c)
//{
// if(c == '\n')
// {
// while (!(UCA1IFG&UCTXIFG)); // 等待标志位
// UCA1TXBUF = '\r';
// }
// while (!(UCA1IFG&UCTXIFG));
// UCA1TXBUF = c;
// return c;
//}
//自定义函数
void getBuf(void)
{
int i=0;
for(i=0;i<RxDataLen;i++)
printStr("RxDataBuf[i]");
}
unsigned short RxChar;
#pragma vector = USCI_A1_VECTOR
__interrupt void ISR_USCI_A1(void)
{
switch(UCA1IV)
{
case 0x00: // Vector 0: No interrupts
break;
case 0x02: // Vector 2: UCRXIFG
{
UCA1IFG &=~ UCRXIFG; // 清除中断标志
RxChar = UCA1RXBUF;
RxDataBuf[RxDataLen] = RxChar;
RxDataLen++;
if(RxChar == '\n')
{
RxDataFlag = 1;
}
break;
}
case 0x04: // Vector 4: UCTXIFG
break;
case 0x06: // Vector 6: UCSTTIFG
break;
case 0x08: // Vector 8: UCTXCPTIFG
break;
default:
break;
}
}
/*---------------------------------------*/
void Initial_Clock(void)
{
/* 外部32.768k使能 */
PJSEL0 |= BIT4;
PJSEL1 &= ~BIT4;
PJSEL0 |= BIT5;
PJSEL1 &= ~BIT5;
/* 使配置完成的IO口生效,从LPMx.5退出 */
PM5CTL0 &= ~LOCKLPM5;
/* 使能时钟寄存器设置 */
CSCTL0_H = CSKEY_H;
FRCTL0 = FRCTLPW|NWAITS_6; //(x可选0~7) for saving For FRAM devices running at higher than 8MHz, FRAM waitstate needs to be configured accordingly.
CSCTL1 = DCOFSEL_6; // DCO = 8M
CSCTL2 = SELA__LFXTCLK + SELS__DCOCLK + SELM__DCOCLK; // ACLK = LFXT ,SMCLK和MCLK=DCO
CSCTL3 = 0; // ACLK/SMCLK/MCLK 分频=1
CSCTL4 = HFXTOFF + VLOOFF + LFXTDRIVE_3; // 关闭HFXT VLO ,打开LFXT
/* 禁止时钟寄存器设置 */
CSCTL0_H = 0;
}
/*--------------------------------------------------*/
char Cmd[] = {"led"};
int Count = 0;
int main(void)
{
int i;
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
Initial_Clock();
Initial_Uart();
__bis_SR_register(GIE);//使能全局中断
/* 使配置完成的IO口生效,从LPMx.5退出 */
PM5CTL0 &= ~LOCKLPM5;
//以下为第一个测试部分,可进行循环发送,连接上位机XCOM,即可接收来自下位机的数据
/*-------------循环发送----------------*/
// while(1)
// {
// putByte('a');
// printStr(" Hello ");
// printf("Shandong University!\n");
// Delay_Ms(1000);
// }
//以下为第二个测试部分,可进行循环接受并发回接受到的数据
/*-------------接收返回发送----------------*/
while(1)
{
if(RxDataFlag){
for(i = 0; i < (RxDataLen-1); i++)
{
if(RxDataBuf[i] == Cmd[i])
{
Count++;
getBuf();
}
}
if(Count == (RxDataLen-1))
{
printStr(" Hello ");
}
Count = 0;
RxDataFlag = 0;
RxDataLen = 0;
}
Delay_Ms(10);
}
// return 0;
}
三、总结
以上就是今天要讲的内容,本文仅仅简单介绍了UART通信协议,以及如何配置及使用UART来进行上下位机的函数和方法。
参考
[1].TI https://www.ti.com/tool/MSP-EXP430FR6989
[2].TI MSP430FR6989用户指南