发送代码
#include <iocc2530.h>#include "hal_mcu.h"#include "hal_assert.h"#include "hal_board.h"#include "hal_rf.h"#include "basic_rf.h"#include <stdio.h>#include "usb.h"#include "12864.h"#include "oled.h"//#define RXuchar Recdata[10];uchar RXTXflag=1;uchar str[20] = "RF_text";uchar temp;uint datanumber = 0;unsigned char buf[10];unsigned char len=0;unsigned char i;uint stringlen = 0;/**********************************初始化串口函数**********************************/void initUART0(void){CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振while (CLKCONSTA & 0x40); //等待晶振稳定CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZSLEEPCMD |= 0x04; //关闭其它无用频率信号PERCFG = 0x00; //位置1P0口P0SEL |= (1 << 3) | (1 << 2); // P0设置为串口P2DIR &= ~((1 << 7) | (1 << 6)); // P0优先作为UART0U0CSR |= (1 << 7);U0GCR |= 9; //指数值,波特率设为9600U0BAUD |= 59; //小数部分59UTX0IF = 1; // usart 0 tx中断U0CSR |= (1 << 6); //接收器使能IEN0 |= (1 << 7) | (1 << 2);}/*******************初始化系统时钟*******************/void InitClock(void){CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振while (CLKCONSTA & 0x40); //等待晶振稳定CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZSLEEPCMD |= 0x04; //关闭其它无用频率信号}/*******************延时*******************/void Delay(unsigned int n){unsigned int tt;for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);}/****************************************************************串口接收一个字符:一旦有数据从串口传至CC2530,则进入中断,将接收到的数据赋值给变量temp.****************************************************************/#pragma vector = URX0_VECTOR__interrupt void UART0_ISR(void){URX0IF = 0;//清中断标志//Recdata[datanumber++] = U0DBUF;//U0DBUF:USART 0 接收/发送数据缓存temp= U0DBUF;}//RF中断初始化void rf_init(){//(1 << 6)硬件产生一个CRC-16(ITU-T)并附加到发送帧。不需要写最后2 个字节到TXBUF。//硬件检查一个CRC-16,并以一个16 位状态字代替RX FIFO,包括一个CRC OK 位。状态字可通过APPEND_DATA_MODE 控制。//(1 << 5)定义无线电是否自动发送确认帧。当autoack 使能,所有经过地址过滤接受的帧都设置确认请求标志,在接收之后自动确认一个有效的CRC12 符号周期。FRMCTRL0 |= (1 << 5) | (1 << 6); //(0x20 | 0x40);//硬件CRC以及AUTO_ACK使能 FRMCTRL0:帧处理TXFILTCFG = 0x09; //0000 1001 设置TX抗混叠过滤器以获得合适的带宽AGCCTRL1 = 0x15; //调整AGC目标值FSCAL1 = 0x00; //获得最佳的EVMRFIRQM0 |= (1 << 6); // RXPKTDONE 中断位使能IEN2 |= (1 << 0); // RF 中断使能EA = 1; //开中断FREQCTRL = 0x0a; //信道选择,选择11信道SHORT_ADDR0 = 0x05; // 0x0005//目标地址过滤期间使用的短地址SHORT_ADDR1 = 0x00;PAN_ID0 = 0x23; // 选择两个设备进行无线通信时的个域网ID: PANID 0x0022//目标地址过滤期间使用的PANIDPAN_ID1 = 0x00;RFST = 0xed; //清除RXFIFO缓冲区并复位解调器RFST = 0xe3; //为RX使能并校准频率合成器FRMFILT0 &= ~(1 << 0); //禁止帧过滤}//通信void tx(){unsigned char i;RFST = 0xe3; //为RX使能并校准频率合成器while (FSMSTAT1 & ((1 << 1) | (1 << 5)));// 等待发送状态不活跃并且没有接收到SFDRFIRQM0 &= ~(1 << 6); //禁止RXPKTDONE接收数据包中断IEN2 &= ~(1 << 0); //禁止RF中断RFST = 0xee; // 清除TXFIFO缓存RFIRQF1 = ~(1 << 1); // 清除 TXDONE 发送完成中断if (Recdata[7]=='N'){RFD = 8 + 2; // 发送的第一个字节是传输的帧长度for (i = 0; i < 8 + 2; i++) //将mac的内容写到RFD中RFD = Recdata[i];}else{RFD = 9 + 2; // 发送的第一个字节是传输的帧长度for (i = 0; i < 9 + 2; i++) //将mac的内容写到RFD中RFD = Recdata[i];}RFST = 0xe9; //校准后使能TXwhile (!(RFIRQF1 & (1 << 1)));//等待传输结束RFIRQF1 = ~(1 << 1); //清除 TXDONE状态RFIRQM0 |= (1 << 6); // 打开RX中断IEN2 |= (1 << 0); //打开RF中断}//接收中断处理#pragma vector = RF_VECTOR__interrupt void rf_isr(void){unsigned char i;//关中断IEN2 &= ~0X01;//接收帧结束if (RFIRQF0 & (1 << 6)){len = RFD; //接收帧长度len &= 0x7f;for (i = 0; i < len; i++) //将接收的数据写入buf中{buf[i] = RFD;Delay(200);}S1CON = 0;// 清RF中断RFIRQF0 &= ~(1 << 6);//清RXPKTDONE中断led1 = ~led1;//LED1等状态改变//设置断点后,程序停止在断点处,但RF仍旧在接收,导致FIFO溢出,无法接收数据,继续运行后再也无法接收。所以要运行一下指令RFST = 0xed; //清除RXFIFO缓冲区并复位解调器}IEN2 |= (1 << 0);}void main(void){P0DIR |= 0x73;OLED_Init();//初始化OLEDOLED_Clear();#if NODE_TYPEOLED_ShowString(30,1,"SEND_ADDR");//发送数据#elseOLED_ShowString(30,1,"RECV_ADDR ");//接收数据#endifLed_Init();//初始化LEDP1DIR = 0x03;//P1控制LEDinitUART0();//初始化串口0函数UartTX_Send_String(str,20);while(1){if(RXTXflag == 1){if(temp!=0){if((temp != '#') && (datanumber < 9)){Recdata[datanumber++] = temp;}else{RXTXflag = 3;Recdata[datanumber++] = '\0';}temp = 0;}}if(RXTXflag == 3){U0CSR &= ~(1<<6);// 不能接收if(Recdata[7]=='N'){//显示OLEDled1=0;UartTX_Send_String(Recdata,datanumber);P0DIR |= 0x73;//Recdata[8]=0;OLED_Init();//初始化OLEDOLED_Clear();OLED_ShowString(30,1,"SEND_ADDR");OLED_ShowString(30,3,"MUSIC_ON ");rf_init();tx();Delay(2000); //延时}else if(Recdata[7]=='F'){led1=1;UartTX_Send_String(Recdata,datanumber);P0DIR |= 0x73;OLED_Init();//初始化OLEDOLED_Clear();OLED_ShowString(30,1,"SEND_ADDR");OLED_ShowString(30,3,"MUSIC_OFF");rf_init();tx();Delay(2000); //延时}U0CSR |= (1<<6);//0x40允许接收RXTXflag = 1;datanumber = 0;}}}
接受代码
#include "ioCC2530.h"#include "oled.h"#include <string.h>#include "type.h"#define RX#define JIEPAI 125 // usunsigned char buf[128];unsigned char len = 0;unsigned char i;uchar str1[8] = "ready.";char Recdata[20];uchar RXTXflag = 1;uchar temp;uint datanum = 0;uint stringlen = 0;//播放音乐模块unsigned char yuepu_cnt = 0; //乐谱数组计数unsigned char k = 0;unsigned int jiepai_cnt = 0;unsigned char sszymmh[] = { //乐谱数组 (音符,音高,节拍)// 凉凉6, 0, 2, 3, 1, 2, 3, 1, 2, 2, 1, 2, 3, 1, 2, 5, 1, 2, 3, 1, 2,2, 1, 2, 3, 1, 4, 6, 0, 8, 7, 0, 2, 7, 0, 2, 7, 0, 2, 1, 1, 2,7, 0, 4, 3, 0, 2, 5, 0, 2, 6, 0, 2, 5, 0, 10,6, 0, 2, 3, 1, 2, 3, 1, 2, 2, 1, 2, 3, 1, 2, 2, 1, 2, 3, 1, 2,5, 1, 4, 3, 1, 4, 2, 1, 2, 3, 1, 2, 5, 1, 2, 5, 1, 4, 6, 1, 4,6, 1, 4, 5, 1, 4, 5, 1, 2, 6, 1, 10};unsigned int YINFU[] = { //音符数组// 低音 00X1DD2, 0X1A94, 0X17AD, 0X1663, 0X13EE, 0X11C1, 0X0FD1,//中音 10x0EF0, 0X0D4F, 0X0BDB, 0X0B31, 0X09F7, 0X08E1, 0X07E8,//高音 20X1912, 0X06A6, 0X05ED, 0X0598, 0X04FC, 0X0470, 0X03F9};//初始化函数声明void Init_Sys(void){CLKCONCMD &= ~0x7f; //晶振设置为32MHZwhile (CLKCONSTA & 0x40); //等待晶振稳定P1SEL &= ~((1 << 0) | (1 << 1));P1DIR |= (1 << 0) | (1 << 1);P2SEL &= ~(1 << 0); // P2_0通用I/OP2DIR |= (1 << 0); //输出beep = 0; //初始低电平 不叫led1 = 0;led2 = 1;}void Init_T1(void) //系统工作频率32MHz,定时器1工作频率4MHz(8分频){T1CCTL0 = (1 << 2) | (1 << 6); //通道0终端使能,比较模式T1CTL = (1 << 2) | (2 << 0); //启动,设8分频,设模模式,1/4Mhz(0.25ms)T1IE = 1; //开T1中断}void Init_T3(void) //系统工作频率32MHz,定时器3工作频率1MHz(32分频){T3CC0 = JIEPAI; //定时器3比较模式模为125usjiepai_cnt = 0;T3CCTL0 = (1 << 2) | (1 << 6); //通道0终端使能,比较模式T3CTL = (5 << 5) | (1 << 4) | (1 << 2) | (2 << 0); //设32分频,启动定时器,复位T3计数器,设模模式T3IE = 1; //开T3中断}void delay_jiepai(void){jiepai_cnt = 0;T3CTL |= (1 << 2) | (1 << 4); //复位并启动T3计数器T3CC0 = JIEPAI;while (jiepai_cnt != (sszymmh[yuepu_cnt + 2] * 1000));}//---------------------------------------------------------------------------------------------------------射频模块-------/*******************初始化系统时钟*******************/void InitClock(void){CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振while (CLKCONSTA & 0x40); //等待晶振稳定CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZSLEEPCMD |= 0x04; //关闭其它无用频率信号}/*******************延时*******************/void Delay(unsigned int n){unsigned int tt;for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);for (tt = 0; tt < n; tt++);}void rf_init(){FRMCTRL0 |= (1 << 5) | (1 << 6); //(0x20 | 0x40);//硬件CRC以及AUTO_ACK使能TXFILTCFG = 0x09; //设置TX抗混叠过滤器以获得合适的带宽AGCCTRL1 = 0x15; //调整AGC目标值FSCAL1 = 0x00; //获得最佳的EVMRFIRQM0 |= (1 << 6); // RXPKTDONE 中断位使能IEN2 |= (1 << 0); // RF 中断使能EA = 1; //开中断FREQCTRL = 0x0a; //信道选择,选择11信道SHORT_ADDR0 = 0x05; // 0x0005 //目标地址过滤期间使用的短地址SHORT_ADDR1 = 0x00;PAN_ID0 = 0x23; // 0x0022 //目标地址过滤期间使用的PANIDPAN_ID1 = 0x00;RFST = 0xed; //清除RXFIFO缓冲区并复位解调器RFST = 0xe3; //为RX使能并校准频率合成器FRMFILT0 &= ~(1 << 0); //禁止帧过滤}//接收中断处理#pragma vector = RF_VECTOR__interrupt void rf_isr(void){unsigned char i;//关中断IEN2 &= ~0X01;//接收帧结束if (RFIRQF0 & (1 << 6)){len = RFD; //接收帧长度len &= 0x7f;for (i = 0; i < len; i++) //将接收的数据写入buf中{buf[i] = RFD;Delay(200);}if (buf[7] == 'N'){P0DIR |= 0x73;OLED_Init(); //初始化OLEDOLED_Clear();OLED_ShowString(30, 1, "RECV_ADDR");OLED_ShowString(30, 3, "MUSIC_ON");delay_ms(250);//放歌led1 = 1;led2 = 0;Init_Sys();Init_T1();k = sszymmh[yuepu_cnt] - 1 + 7 * sszymmh[yuepu_cnt + 1];Init_T3();EA = 1; //开总中断}else if (buf[7] == 'F'){//停止播放beep = 0;Delay(2000);Delay(2000);Delay(2000);T1IE = 0;T3IE = 0;beep = 0;jiepai_cnt = 0;yuepu_cnt = 0;led1 = 1;led2 = 1;// OLEDP0DIR |= 0x73;OLED_Init(); //初始化OLEDOLED_Clear();OLED_ShowString(30, 1, "RECV_ADDR");OLED_ShowString(30, 3, "MUSIC_OFF");delay_ms(250);}S1CON = 0; // 清RF中断RFIRQF0 &= ~(1 << 6); //清 RXPKTDONE中断//设置断点后,程序停止在断点处,但RF仍旧在接收,导致FIFO溢出,无法接收数据,继续运行后再也无法接收。所以要运行一下指令RFST = 0xed; //清除RXFIFO缓冲区并复位解调器}IEN2 |= (1 << 0);}#pragma vector = T1_VECTOR__interrupt void T1_ISR(void){if (buf[7] == 'F') //如果是F则{beep = 0; //初始低电平 不叫led1 = 0;led2 = 0;yuepu_cnt = 0;jiepai_cnt = 0;T1CC0H = 0; //定时器1 通道0 捕获/比较值高字节T1CC0L = 0; //定时器1 通道1 捕获/比较值低字节}else{beep = !beep; // 1电平 叫T1CC0H = YINFU[k] >> 8;T1CC0L = YINFU[k] & 0xFF;}}#pragma vector = T3_VECTOR__interrupt void T3_ISR(void){// T3CC0 = JIEPAI;jiepai_cnt++;if (jiepai_cnt >= (sszymmh[yuepu_cnt + 2] * 1000)) //节拍数组 1/4 单位:ms{jiepai_cnt = 0;yuepu_cnt += 3;if (yuepu_cnt >= sizeof(sszymmh))yuepu_cnt = 0;k = sszymmh[yuepu_cnt] - 1 + 7 * sszymmh[yuepu_cnt + 1];T1CC0H = YINFU[k] >> 8;T1CC0L = YINFU[k] & 0xFF;led1 = !led1; //播放一个音符交替闪烁led2 = !led2; //}}int main(void){EA = 0;InitClock(); //初始化系统时钟rf_init();EA = 1;}
任务
每组两个同学,使用两个IMOTE CC2530 无线通信节点板(无线发送端/接收端节点)与PC机。具体任务如下:
PC机通过串口通信软件向无线发送端节点的单片机发送字符串”MUSIC_ON”或”MUSIC_OFF”。
无线发送端节点:无线发送端单片机节点接收到PC机发送的字符串后在OLED显示屏上显示字符串内容,同时通过无线RF向无线接收端节点发送字符串数据。
无线发接收端节点:无线发接收端节点接收通过无线RF方式发送的字符数据,在OLED显示屏上显示字符串内容,并播放或停止播放音乐。
OLED
| 功能引脚 | 描述 |
|---|---|
| VCC | 3.3V/5V电源正 |
| GND | 电源地 |
| NC | NC |
| DIN | SPI数据输入 |
| CLK | SPI时钟输入 |
| CS | 片选,低电平有效 |
| RST | 复位 |
GND:电源地
VCC:2.2V~5.5V
SCL(D0):CLK 时钟(高电平2.2V~5.5V)
SDA(D1):MOSI 数据(高电平2.2V~5.5V)
RST:复位(高电平2.2V~5.5V)
D/C:数据/命令(高电平2.2V~5.5V)

