打印
[MCU]

TI MSP430 如何实现模拟串口通信

[复制链接]
640|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
八层楼|  楼主 | 2020-8-5 17:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

1、背景:

很多时候由于硬件资源有限,但又需要使用串口通信,此时可以考虑使用模拟串口;

2、前提:

要实现特定bps的串口速率,需要相应频率的定时器,保证误码率在可以接受的范围内;

例如:

1MHz的时钟最高可模拟9600bps的通信速率:1M/9600 = 104  误码率<1%

3、参考代码:



  • //******************************************************************************



  • //  ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO



  • //  //* An external watch crystal is required on XIN XOUT for ACLK *//  



  • //



  • //               MSP430G2xx1



  • //            -----------------



  • //        /|\|              XIN|-



  • //         | |                 | 32kHz



  • //         --|RST          XOUT|-



  • //           |                 |



  • //           |   CCI0B/TXD/P1.1|-------->



  • //           |                 | 9600 8N1



  • //           |   CCI0A/RXD/P1.2|<--------



  • //



  • //******************************************************************************







  • #include <msp430.h>







  • //------------------------------------------------------------------------------



  • // Hardware-related definitions



  • //------------------------------------------------------------------------------



  • #define UART_TXD   0x02                     // TXD on P1.1 (Timer0_A.OUT0)



  • #define UART_RXD   0x04                     // RXD on P1.2 (Timer0_A.CCI1A)











  • //------------------------------------------------------------------------------



  • // Conditions for 9600 Baud SW UART, SMCLK = 1MHz



  • //------------------------------------------------------------------------------



  • #define UART_TBIT_DIV_2     (1000000 / (9600 * 2))



  • #define UART_TBIT           (1000000 / 9600)











  • //------------------------------------------------------------------------------



  • // Global variables used for full-duplex UART communication



  • //------------------------------------------------------------------------------



  • unsigned int txData;                        // UART internal variable for TX



  • unsigned char rxBuffer;                     // Received UART character











  • //------------------------------------------------------------------------------



  • // Function prototypes



  • //------------------------------------------------------------------------------



  • void TimerA_UART_init(void);



  • void TimerA_UART_tx(unsigned char byte);



  • void TimerA_UART_print(char *string);











  • //------------------------------------------------------------------------------



  • // main()



  • //------------------------------------------------------------------------------



  • int main(void)



  • {



  •     WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer



  •     if (CALBC1_1MHZ==0xFF)                                        // If calibration constants erased



  •     {                                                                                       



  •       while(1);                             // do not load, trap CPU!!       



  •     }



  •     DCOCTL = 0;                             // Select lowest DCOx and MODx settings



  •     BCSCTL1 = CALBC1_1MHZ;



  •     DCOCTL = CALDCO_1MHZ;











  •     P1OUT = 0x00;                           // Initialize all GPIO



  •     P1SEL = UART_TXD + UART_RXD;            // Timer function for TXD/RXD pins



  •     P1DIR = 0xFF & ~UART_RXD;               // Set all pins but RXD to output



  •     P2OUT = 0x00;



  •     P2SEL = 0x00;



  •     P2DIR = 0xFF;











  •     __enable_interrupt();







  •     TimerA_UART_init();                     // Start Timer_A UART



  •     TimerA_UART_print("G2xx1 TimerA UART\r\n");



  •     TimerA_UART_print("READY.\r\n");







  •     for (;;)



  •     {



  •         // Wait for incoming character



  •         __bis_SR_register(LPM0_bits);







  •         // Update board outputs according to received byte



  •         if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01;    // P1.0



  •         if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08;    // P1.3



  •         if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10;    // P1.4



  •         if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20;    // P1.5



  •         if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40;    // P1.6



  •         if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80;    // P1.7



  •         if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~0x40;    // P2.6



  •         if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~0x80;    // P2.7







  •         // Echo received character



  •         TimerA_UART_tx(rxBuffer);



  •     }



  • }



  • //------------------------------------------------------------------------------



  • // Function configures Timer_A for full-duplex UART operation



  • //------------------------------------------------------------------------------



  • void TimerA_UART_init(void)



  • {



  •     TACCTL0 = OUT;                          // Set TXD Idle as Mark = '1'



  •     TACCTL1 = SCS + CM1 + CAP + CCIE;       // Sync, Neg Edge, Capture, Int



  •     TACTL = TASSEL_2 + MC_2;                // SMCLK, start in continuous mode



  • }



  • //------------------------------------------------------------------------------



  • // Outputs one byte using the Timer_A UART



  • //------------------------------------------------------------------------------



  • void TimerA_UART_tx(unsigned char byte)



  • {



  •     while (TACCTL0 & CCIE);                 // Ensure last char got TX'd



  •     TACCR0 = TAR;                           // Current state of TA counter



  •     TACCR0 += UART_TBIT;                    // One bit time till first bit



  •     TACCTL0 = OUTMOD0 + CCIE;               // Set TXD on EQU0, Int



  •     txData = byte;                          // Load global variable



  •     txData |= 0x100;                        // Add mark stop bit to TXData



  •     txData <<= 1;                           // Add space start bit



  • }











  • //------------------------------------------------------------------------------



  • // Prints a string over using the Timer_A UART



  • //------------------------------------------------------------------------------



  • void TimerA_UART_print(char *string)



  • {



  •     while (*string) {



  •         TimerA_UART_tx(*string++);



  •     }



  • }



  • //------------------------------------------------------------------------------



  • // Timer_A UART - Transmit Interrupt Handler



  • //------------------------------------------------------------------------------



  • #pragma vector = TIMERA0_VECTOR



  • __interrupt void Timer_A0_ISR(void)



  • {



  •     static unsigned char txBitCnt = 10;











  •     TACCR0 += UART_TBIT;                    // Add Offset to CCRx



  •     if (txBitCnt == 0) {                    // All bits TXed?



  •         TACCTL0 &= ~CCIE;                   // All bits TXed, disable interrupt



  •         txBitCnt = 10;                      // Re-load bit counter



  •     }



  •     else {



  •         if (txData & 0x01) {



  •           TACCTL0 &= ~OUTMOD2;              // TX Mark '1'



  •         }



  •         else {



  •           TACCTL0 |= OUTMOD2;               // TX Space '0'



  •         }



  •         txData >>= 1;



  •         txBitCnt--;



  •     }



  • }      



  • //------------------------------------------------------------------------------



  • // Timer_A UART - Receive Interrupt Handler



  • //------------------------------------------------------------------------------



  • #pragma vector = TIMERA1_VECTOR



  • __interrupt void Timer_A1_ISR(void)



  • {



  •     static unsigned char rxBitCnt = 8;



  •     static unsigned char rxData = 0;











  •     switch (__even_in_range(TAIV, TAIV_TAIFG)) { // Use calculated branching



  •         case TAIV_TACCR1:                        // TACCR1 CCIFG - UART RX



  •             TACCR1 += UART_TBIT;                 // Add Offset to CCRx



  •             if (TACCTL1 & CAP) {                 // Capture mode = start bit edge



  •                 TACCTL1 &= ~CAP;                 // Switch capture to compare mode



  •                 TACCR1 += UART_TBIT_DIV_2;       // Point CCRx to middle of D0



  •             }



  •             else {



  •                 rxData >>= 1;



  •                 if (TACCTL1 & SCCI) {            // Get bit waiting in receive latch



  •                     rxData |= 0x80;



  •                 }



  •                 rxBitCnt--;



  •                 if (rxBitCnt == 0) {             // All bits RXed?



  •                     rxBuffer = rxData;           // Store in global variable



  •                     rxBitCnt = 8;                // Re-load bit counter



  •                     TACCTL1 |= CAP;              // Switch compare to capture mode



  •                     __bic_SR_register_on_exit(LPM0_bits);  // Clear LPM0 bits from 0(SR)



  •                 }



  •             }



  •             break;



  •     }



  • }



  • //------------------------------------------------------------------------------



使用特权

评论回复

相关帖子

沙发
10299823| | 2020-8-5 20:14 | 只看该作者
串口通信,或者 IIC 通信,应该是由专门的硬件,来完成的

使用特权

评论回复
板凳
jimmhu| | 2020-8-5 20:14 | 只看该作者
用IO模拟SPI或者I2C都可以

使用特权

评论回复
地板
lihuami| | 2020-8-5 20:14 | 只看该作者
            

使用特权

评论回复
5
xiaoyaozt| | 2020-8-5 20:15 | 只看该作者
用单片机IO口模拟的,只能是半双工的

使用特权

评论回复
6
uptown| | 2020-8-5 20:15 | 只看该作者
用来模拟串口接收的I/O是两个外中断口 之一,可以做到接收中断

使用特权

评论回复
7
cehuafan| | 2020-8-5 20:15 | 只看该作者
用一个普通IO口作为TXD发送口,外部中断口作为RXD接收口

使用特权

评论回复
8
usysm| | 2020-8-5 20:16 | 只看该作者
单片机一般只有一个串行接口  

使用特权

评论回复
9
typeof| | 2020-8-5 20:16 | 只看该作者
用延时来实现定时  

使用特权

评论回复
10
yujielun| | 2020-8-5 20:17 | 只看该作者
模拟串口可行性怎么样   

使用特权

评论回复
11
htmlme| | 2020-8-5 20:17 | 只看该作者
定时器是最简单的方式了   

使用特权

评论回复
12
uptown| | 2020-8-5 20:17 | 只看该作者
边沿触发的移位寄存器

使用特权

评论回复
13
xiaoyaozt| | 2020-8-5 20:17 | 只看该作者
主要就是定时器实现波特率定时  

使用特权

评论回复
14
cehuafan| | 2020-8-5 20:17 | 只看该作者
就可以模拟串口通讯了。  

使用特权

评论回复
15
lihuami| | 2020-8-5 20:17 | 只看该作者
谢谢楼主分享的资料了。   

使用特权

评论回复
16
usysm| | 2020-8-5 20:17 | 只看该作者
模拟串口主要是先要考虑到波特率和数据格式  

使用特权

评论回复
17
jimmhu| | 2020-8-5 20:18 | 只看该作者
如果一定要用延时的方式来接收

使用特权

评论回复
18
typeof| | 2020-8-5 20:18 | 只看该作者
示例软件模拟串口的方法  

使用特权

评论回复
19
10299823| | 2020-8-5 20:18 | 只看该作者
可以考虑使用模拟串口  

使用特权

评论回复
20
yujielun| | 2020-8-5 20:18 | 只看该作者
学习一下。               

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

4046

帖子

2

粉丝