MSP430g2553硬件UART(基于官方例程的修改)
[复制链接]
本帖最后由 fish001 于 2020-3-12 22:09 编辑
一开始官方例程的UART_Keyboard在电脑上老是运行不了,于是就自己上网学习了一下UART实现的具体过程,修改了一下官方的例程代码,在这里记录一下
其实官方例程有时候运行不起在于:
1.波特率设置
2.官方的Rx中断处理函数并不适用于所有串口调试程序
3.注意跳线帽!!!RX接TX,TX接RX!!
官方例程的UART程序流程
这里我用onenote大致画了一下
对于Tx和Rx中断:
当单片机内部的Rx_buf寄存器(一般来说8bits)收到了无符号字符型数据时,就会产生Rx中断,系统调用Rx中断处理函数,也就是说当收到一个字符串型数据时系统会产生多次Rx中断。
当单片机内部的Tx_buf寄存器(也是8bits)将数据发送完毕时,会产生Tx中断,同理,当发送一个字符串型数据时系统会产生多次Tx中断。
对于FIFO:
也就是申明的存储字符型数据的字符数组
RxFIFO用来读取Rx_buf传来的字符型数据,并供给CPU进行读取
TxFIFO用来存放CPU准备发送的数据,并让Tx_buf进行读取
所以每个FIFO要用三个变量来表示:读指针位置,写指针位置,已有的容量大小
代码分析
main.c
可以看出来主函数只起到了关闭看门狗的作用,精华都在初始化UART函数中
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
USCI_A0_init();
}
USCI_A0_init()
void USCI_A0_init(void){
//配置时钟
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set DCO 实际时钟频率1048576Hz
DCOCTL = CALDCO_1MHZ;
//配置GPIO寄存器
P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
//配置串口寄存器
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 104; // 1MHz 9600
UCA0BR1 = 0; // 1MHz 9600
UCA0MCTL =UCBRS_0;//UCBRS0; // Modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
//开中断
IE2 |= UCA0RXIE+UCA0TXIE; //使能TX,RX中断
_enable_interrupts();
//设置单片机工作模式
_bis_SR_register(LPM0_bits); //单片机工作在LPM0功耗模式
}
在这里有几个比较重要的寄存器需要说明:
UCA0CTL1:
时钟源选择和软件复位使能
UCSSEL_2:时钟源一般可以选择ACLK和SMCLK(官网例程选择了ACLK,这里选择SMCLK)
至于软件复位的那位UCSWRST:0被禁用。USCI复位被释放用于运行。1被启用。USCI逻辑保持在复位状态。意思就是说在单片机复位之后 如果 此位是0 那么串口可以正常工作 为1 即保持 复位状态 复位状态后 此位为1 就是说 复位后如果不清零 那么串口是不会工作的
UCA0BR0,UCA0BR1
波特率配置寄存器
给定一个BRCLK时钟源,波特率用来决定需要分频的因子N:
N = fBRCLK/Baudrate
分频因子N通常是非整数值,因此至少一个分频器和一个调制阶段用来尽可能的接近N。
所以:
UCA0BRX用来存放N的整数部分,其中BR0存放低位,BR1存放高位(这里的SMCLK时钟源频率大概为32khz)
UCA0MCTL
波特率调整控制器
有整数部分时不够的,还要有小数部分!
UCBRSx = round( ( N – INT(N) ) × 8 )
注意这个寄存器的最后一位时用来选择模式的!!我们这里用0模式!
给出一个计算列题:
例2:32768Hz频率下驱动以2400波特率异步通ACLK = REFO = ~32768Hz, MCLK = SMCLK = DCO ~1.045MHz
N = fBRCLK/Baudrate = 32768/2400 = ~13.65
UCBRx = INT(N) = INT(13.65) = 13
UCBRSx = round( ( N – INT(N) )×8 ) = round( ( 13.65 – 13) × 8 )=round(5.2)=5
UCA0CTL1 |= UCSSEL_1; // 选ACLK为时钟
UCAxBR0 = 13;
UCAxBR1 = 0 ;
UCAxMCTL = 0x0A;//7-4:
UCBRFx,3-1:UCBRSx,0:UCOS16
UCBRSx为寄存器UCAxMCTL的1-3位,所以写入0x0A(00001010)
定义中断处理函数
//====================================中断处理函数============================================
//TX中断处理函数
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
// while(!(IFG2 & UCA0TXIFG)); //待发送为空
IFG2&=~UCA0TXIFG; // 手动清除标志位,标志位置零
UART_OnTx(); // 调用Tx事件处理函数
}
//RX中断处理函数
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
// while (!(IFG2&UCA0TXIFG)); // 等待发送完成
IFG2&=~UCA0RXIFG; // USCI_A0 TX buffer ready?
UART_OnRx(); //!!!!!!!EVENT.H函数!
// UCA0TXBUF = UCA0RXBUF; // TX -> RXed character
}
这里改写了一下中断处理函数,想要试一试配置成功与否的话可以直接在Rx中断里面写:UCA0TXBUF = UCA0RXBUF;收到啥发啥
/******************************************************************************************************
* 名 称:UART_OnRx()
* 功 能:UART的Rx事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:对接收到的数据,区别对待进行处理
* 范 例:无
******************************************************************************************************/
void UART_OnRx()
{
unsigned char Temp=0; //定义读取的RX_buf中的8bits数
Temp=UCA0RXBUF; //读取RX_buf中的数据
//判断RXBUF中的收到的数据 1:回车,匹配数据 0:不是回车,放入FIFO中
if(Temp==0x0d) //如果是回车
{
if(Rx_FIFO_DataNum>0) //如果已经收到数据
{
Command_match(); //判断指令
// Rx_FIFO_Clear(); //读取完一次指令,清零
}
else{
UART_SendString(String1); //没收到任何数据
}
}
else //收到的不是回车,则读取数据
{
Rx_FIFO_WriteChar(Temp); //写入数据到FIFO中
}
}
/******************************************************************************************************
* 名 称:UART_OnTx()
* 功 能:UART的Tx事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:Tx_FIFO里有数据就将数据移到Tx Buffer寄存器中去
* 范 例:无
******************************************************************************************************/
void UART_OnTx(void)
{
unsigned char Temp;
if(Tx_FIFO_DataNum>0) //数据量==0为结束条件
{
Tx_FIFO_ReadChar(&Temp); //调用FIFO库函数,返回8bit数据
UCA0TXBUF= Temp; //
}
}
|