// Haybin_Wu // Shenitech-RD // 2016.5 // Built with IAR Embedded Workbench v6.2 //****************************************************************************** // Modify by Qian Xianghong // 2020.10 // 修改日志:将无线模块做成串口和RF双向透传模式。 //****************************************************************************** #include #include #include #include #include "FR2433-RFSX.h" #include "RF_SX1276.h" // 射频配置参数 lora_param_t Lora_Param; #define TRAN_BUF_SIZE (1024) // 用UA1串口做打印输出,方便调试 char printBuf[200]; void uart_print() { #if 0 // 打印串口的2个引脚用作MD0、MD1模式选择 char *p = printBuf; while(*p) { if(*p == '\n') // 换行前添加回车 { while(!(UCA1IFG & UCTXIFG)); UCA1TXBUF = '\r'; } while(!(UCA1IFG & UCTXIFG)); UCA1TXBUF = *p++; } #endif } // 可变参数的宏定义 #define PRINTF(format, ...) \ { \ snprintf(printBuf, sizeof(printBuf), format, ##__VA_ARGS__); \ uart_print(); \ } // UA0接收上位机数据的buf uint8_t UA0_RxBuf[TRAN_BUF_SIZE] = {0}; uint16_t UA0_RxBuf_Length = 0; uint16_t UA0_RxBuf_offset = 0; // UA0接收超时 volatile uint8_t UA0_Rx_Timeout = 1; // RF接收数据的buf uint8_t RF_RxBuf[TRAN_BUF_SIZE] = {0}; uint16_t RF_RxBuf_Length = 0; uint16_t RF_RxBuf_offset = 0; // RF接收超时标志 volatile uint8_t RF_Rx_Timeout = 1; //////////////////////////////////////////////////////////////////////////////// // 主串口初始化 void UA0_Init(uint32_t baudrate) { // Configure UART UCA0CTLW0 |=(UCSSEL__SMCLK+UCSWRST);//UCPEN+UCPAR+ // Baud Rate calculation if(baudrate == 115200) { UCA0BR0 = 4; // 8000000/16/115200//这位大于16 UCOS16位要置位 UCA0BR1 = 0; // Fractional portion = 0.44444 UCA0MCTLW = 0x5500 | UCOS16 | UCBRF_5;//微调Baud Rate } else if(baudrate == 38400) { UCA0BR0 = 13; // 8000000/16/38400 /这位大于16 UCOS16位要置位 UCA0BR1 = 0; // Fractional portion = 0.33333 UCA0MCTLW = 0x8400 | UCOS16 | UCBRF_0;//微调Baud Rate } else { UCA0BR0 = 52; // 8000000/16/9600 /这位大于16 UCOS16位要置位 UCA0BR1 = 0; // Fractional portion = 0.33333 UCA0MCTLW = 0x4900 | UCOS16 | UCBRF_1;//微调Baud Rate } UCA0CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt } // 主串口应答(配置命令) void UA0_Response(char *s) { while(*s) { while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = *s++; } // 等待发送结束 while(!(UCA0IFG & UCTXCPTIFG)); DelayMs(2); } //////////////////////////////////////////////////////////////////////////////// //主函数 //////////////////////////////////////////////////////////////////////////////// int main(void) { uint8_t sendCh; WDTCTL = (WDTPW | WDTHOLD); // Stop WDT // Port Configuration all un-used pins to output low P1DIR = 0xFF; P2DIR = 0xFF; P3DIR = 0xFF; P1OUT = 0x00; P2OUT = 0x00; P3OUT = 0x00; PM5CTL0 &= ~LOCKLPM5;//开引脚功能 // Configure DCO Clock //外部时钟源启动 P2SEL0 |= (BIT0 | BIT1); // set XT1 pin as second function do { CSCTL7 &= ~(XT1OFFG | DCOFFG); // Clear XT1 and DCO fault flag SFRIFG1 &= ~OFIFG; } while (SFRIFG1 & OFIFG); // Test oscillator fault flag //上面清除标志有助于降低功耗 __bis_SR_register(SCG0); // disable FLL CSCTL3 |= SELREF__XT1CLK; // 外部 32768hz reference source CSCTL0 = 0; // clear DCO and MOD registers CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first CSCTL1 |= DCORSEL_3; //DCO=8Mhz CSCTL2 = FLLD_0 + 243; // DCODIV = 8MHz __delay_cycles(3); __bic_SR_register(SCG0); // enable FLL while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked CSCTL4 = SELREF__XT1CLK + SELMS__DCOCLKDIV;// set XT1CLK(32768Hz) as ACLK source & MCLK/SMCLK=DCO //Timer0_A0 setup TA0CCTL0 = CCIE; // TACCR0 interrupt enabled TA0CCR0 = 32768 / 32; // 串口接收超时: 1000/32=31.25ms TA0CTL = MC__STOP | TACLR; // Stop mode, Clear counter //Timer1_A0 setup TA1CCTL0 = CCIE; // TACCR0 interrupt enabled TA1CCR0 = 32768 / 4; // RF接收超时: 1000/4=250ms TA1CTL = MC__STOP | TACLR; // Stop mode, Clear counter // 设置无线模块缺省参数 Lora_Param.sof = 0xC2; Lora_Param.addr = 0xADF2; // 通信地址0xADF2 Lora_Param.sf = 6; // sf=12 Lora_Param.baud = 3; // 9600 Lora_Param.cr = 0; // cr=4/5 Lora_Param.ch = 9; // 479MHz Lora_Param.power = 1; // 17dBm Lora_Param.freqcast = 0; // freqcast off Lora_Param.bw = 9; // 500kHz Lora_Param.unicast = 0; // unicast off // Configure UART pins P1SEL1 &= ~(BIT4 | BIT5); // set 2-UART pin as second function P1SEL0 |= (BIT4 | BIT5); // set 2-UART pin as second function if(Lora_Param.baud == 7) UA0_Init(115200); else if(Lora_Param.baud == 5) UA0_Init(38400); else UA0_Init(9600); #if 0 // 配置打印串口 // Configure UART pins P2SEL1 &= ~(BIT5 | BIT6); // set 2-UART pin as second function P2SEL0 |= (BIT5 | BIT6); // set 2-UART pin as second function // Configure UART UCA1CTLW0 |=(UCSSEL__SMCLK+UCSWRST);//UCPEN+UCPAR+ // Baud Rate calculation UCA1BR0 = 4; // 8000000/16/115200//这位大于16 UCOS16位要置位 UCA1BR1 = 0; // Fractional portion = 0.44444 UCA1MCTLW = 0x5500 | UCOS16 | UCBRF_5;//微调Baud Rate UCA1CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA1IE |= UCRXIE; // Enable USCI_A0 RX interrupt // 打印复位原因(电源引起,不包括看门狗) PRINTF("\nModule reseted: %04X\n", PMMIFG); #else // 配置MD0、MD1模式 P2SEL1 &= ~(BIT3 | BIT5 | BIT6); // set 2-UART pin as GPIO P2SEL0 &= ~(BIT3 | BIT5 | BIT6); // set 2-UART pin as GPIO P2DIR &= ~(BIT5 | BIT6); // Input P2REN |= (BIT5 | BIT6); // enable pull P2OUT &= ~(BIT5 | BIT6); // pull-down P2DIR |= BIT3; // Output P2OUT |= BIT3; // Output high #endif _EINT(); #if 0 // 打印复位原因(电源引起,不包括看门狗) RF_RxBuf[0] = PMMIFG >> 8; RF_RxBuf[1] = PMMIFG & 0xFF; RF_RxBuf_Length = 2; RF_RxBuf_offset = 0; UCA0IE |= UCTXIE; while(UCA0IE & UCTXIE); #endif // 读寄存器,清除复位原因 SYSRSTIV; //无线模块初始化 uint8_t try_count = 3; //最多初始化3次 while(try_count) { if(SX127x_initLora(&Lora_Param) == NORMAL) break; try_count--; } if(try_count == 0) //无线初始化失败处理 { //P3OUT ^= 0xC0; LPM4; } // 初始处于接收模式 LSD_RF_RXmode(RF_PAYLOAD_LEN); // 默认发送信道 sendCh = Lora_Param.ch; // 开启看门狗: 超时时间为2^27/SMCLK,在8000000主频下约为16s WDTCTL = (WDTPW | WDTCNTCL | WDTIS_1); while(1) { #if 1 // TODO: 喂狗 WDTCTL = (WDTPW | WDTCNTCL | WDTIS_1); // 配置模式 if((P2IN & (BIT5 | BIT6)) == (BIT5 | BIT6)) { if(UA0_RxBuf_Length - UA0_RxBuf_offset >= sizeof(Lora_Param)) { if(UA0_RxBuf[UA0_RxBuf_offset] == 0xC2) { // 保存参数 memmove(&Lora_Param, UA0_RxBuf + UA0_RxBuf_offset, sizeof(Lora_Param)); // 颠倒地址高低字节 Lora_Param.addr = (Lora_Param.addr << 8) | (Lora_Param.addr >> 8); //无线模块初始化 uint8_t try_count = 3; //最多初始化3次 while(try_count) { // 其它参数有变化,无线模块初始化 if(SX127x_initLora(&Lora_Param) == NORMAL) break; try_count--; } if(try_count == 0) //无线初始化失败处理 { //P3OUT ^= 0xC0; LPM4; } // 默认处于接收模式 LSD_RF_RXmode(RF_PAYLOAD_LEN); // 默认发送信道 sendCh = Lora_Param.ch; // 应答配置命令 UA0_Response("OK\r\n"); // 改变串口波特率 if(Lora_Param.baud == 7) UA0_Init(115200); else if(Lora_Param.baud == 5) UA0_Init(38400); else UA0_Init(9600); } UA0_RxBuf_offset = UA0_RxBuf_Length; } } // 透传模式 else if((P2IN & (BIT5 | BIT6)) == 0) #endif { if(UA0_RxBuf_Length > UA0_RxBuf_offset) { // 定点传输,指定目标地址和信道发送 if(Lora_Param.unicast) // 定点发送 { if(UA0_RxBuf_offset == 0 && UA0_RxBuf_Length > 3) sendCh = UA0_RxBuf[2]; } else if(Lora_Param.freqcast) // 指定信道发送 { if(UA0_RxBuf_offset == 0 && UA0_RxBuf_Length > 1) { sendCh = UA0_RxBuf[0]; Lora_Param.ch= UA0_RxBuf[1]; UA0_RxBuf_offset = 2; // 不发送第1发个字节 } } if(UA0_RxBuf_Length - UA0_RxBuf_offset >= RF_PAYLOAD_LEN) { LSD_RF_FreqSet(sendCh); LSD_RF_SendPacket(UA0_RxBuf + UA0_RxBuf_offset, RF_PAYLOAD_LEN); UA0_RxBuf_offset += RF_PAYLOAD_LEN; PRINTF("Send packet\n"); // 切换到接收模式 LSD_RF_FreqSet(Lora_Param.ch); LSD_RF_RXmode(RF_PAYLOAD_LEN); } else if(UA0_Rx_Timeout) { LSD_RF_FreqSet(sendCh); LSD_RF_SendPacket(UA0_RxBuf + UA0_RxBuf_offset, UA0_RxBuf_Length - UA0_RxBuf_offset); UA0_RxBuf_offset = UA0_RxBuf_Length; PRINTF("Send packet\n"); // 切换到接收模式 LSD_RF_FreqSet(Lora_Param.ch); LSD_RF_RXmode(RF_PAYLOAD_LEN); } } } if(UA0_Rx_Timeout && UA0_RxBuf_offset == UA0_RxBuf_Length) P2OUT |= BIT3; // Output high } } // Port 1 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void) #else #error Compiler not supported! #endif { uint8_t offset = 0; uint8_t len[1] = {0}; uint8_t buf[RF_PAYLOAD_LEN]; if(DIO0_IFG&DIO0_BIT) //数据传输中断处理 { // 清中断 DIO0_IFG &= ~DIO0_BIT; // 读取RF数据 LSD_RF_RxVariPacket(buf, len); //接收可变数据包,如果速率为大速率,只能用接收固定数据包长度 if(len[0] == 0) return; TA1CTL = MC__STOP | TACLR; // 停止定时器,复位计数器 TA1CTL = TASSEL__ACLK | MC__UP; // 重新开始计时 offset = 0; if(RF_Rx_Timeout) // 新的一组数据到来 { RF_Rx_Timeout = 0; // 复位缓冲区 RF_RxBuf_Length = 0; RF_RxBuf_offset = 0; if(Lora_Param.unicast) { // 定点传输,地址和信道校验失败 if(len[0] <= 3 || buf[2] != Lora_Param.ch || ((buf[0] << 8) | buf[1]) != Lora_Param.addr) return; // 前3个字符丢掉 offset = 3; len[0] -= offset; } } PRINTF("Recv packet\n"); // 透传模式 if((P2IN & (BIT5 | BIT6)) == 0) { if(RF_RxBuf_Length + len[0] <= TRAN_BUF_SIZE) { memmove(RF_RxBuf + RF_RxBuf_Length, buf + offset, len[0]); // 中断方式向串口转发 RF_RxBuf_Length += len[0]; UCA0IE |= UCTXIE; } } } } // Timer0 A0 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer0_A0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer0_A0_ISR (void) #else #error Compiler not supported! #endif { // 停止定时器,复位计数器 TA0CTL = MC__STOP | TACLR; // 串口接收超时 UA0_Rx_Timeout = 1; } // Timer1 A0 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = TIMER1_A0_VECTOR __interrupt void Timer1_A0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer1_A0_ISR (void) #else #error Compiler not supported! #endif { // 停止定时器,复位计数器 TA1CTL = MC__STOP | TACLR; // RF接收超时 RF_Rx_Timeout = 1; } // UAR0 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_A0_VECTOR __interrupt void USCI_A0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void) #else #error Compiler not supported! #endif { // 接收中断 if((UCA0IE & UCRXIE) && (UCA0IFG & UCRXIFG)) { uint8_t c = UCA0RXBUF; TA0CTL = MC__STOP | TACLR; // 停止定时器,复位计数器 TA0CTL = TASSEL__ACLK | MC__UP; // 重新开始计时 if(UA0_Rx_Timeout) // 新的一组数据到来 { UA0_Rx_Timeout = 0; // 复位缓冲区 UA0_RxBuf_Length = 0; UA0_RxBuf_offset = 0; } if(UA0_RxBuf_Length < TRAN_BUF_SIZE) { #if 1 // 配置模式 if((P2IN & (BIT5 | BIT6)) == (BIT5 | BIT6)) { // 第1个字符必须为0xC2 if(UA0_RxBuf_Length > 0 || c == 0xC2) UA0_RxBuf[UA0_RxBuf_Length++] = c; } // 透传模式 else if((P2IN & (BIT5 | BIT6)) == 0) #endif { // 主函数透传 UA0_RxBuf[UA0_RxBuf_Length++] = c; } P2OUT &= ~BIT3; // Output low } } // 发送中断 if((UCA0IE & UCTXIE) && (UCA0IFG & UCTXIFG)) { UCA0TXBUF = RF_RxBuf[RF_RxBuf_offset++]; // 发送字符 if(RF_RxBuf_offset >= RF_RxBuf_Length) // 全部发送完 { // 禁止中断 UCA0IE &= ~UCTXIE; } } }