发送代码
#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 RX
uchar 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; //设置系统主时钟频率为32MHZ
SLEEPCMD |= 0x04; //关闭其它无用频率信号
PERCFG = 0x00; //位置1P0口
P0SEL |= (1 << 3) | (1 << 2); // P0设置为串口
P2DIR &= ~((1 << 7) | (1 << 6)); // P0优先作为UART0
U0CSR |= (1 << 7);
U0GCR |= 9; //指数值,波特率设为9600
U0BAUD |= 59; //小数部分59
UTX0IF = 1; // usart 0 tx中断
U0CSR |= (1 << 6); //接收器使能
IEN0 |= (1 << 7) | (1 << 2);
}
/*******************
初始化系统时钟
*******************/
void InitClock(void)
{
CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振
while (CLKCONSTA & 0x40)
; //等待晶振稳定
CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ
SLEEPCMD |= 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; //获得最佳的EVM
RFIRQM0 |= (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//目标地址过滤期间使用的PANID
PAN_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)));// 等待发送状态不活跃并且没有接收到SFD
RFIRQM0 &= ~(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; //校准后使能TX
while (!(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();//初始化OLED
OLED_Clear();
#if NODE_TYPE
OLED_ShowString(30,1,"SEND_ADDR");//发送数据
#else
OLED_ShowString(30,1,"RECV_ADDR ");//接收数据
#endif
Led_Init();//初始化LED
P1DIR = 0x03;//P1控制LED
initUART0();//初始化串口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'){
//显示OLED
led1=0;
UartTX_Send_String(Recdata,datanumber);
P0DIR |= 0x73;
//Recdata[8]=0;
OLED_Init();//初始化OLED
OLED_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();//初始化OLED
OLED_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 // us
unsigned 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[] = { //音符数组
// 低音 0
0X1DD2, 0X1A94, 0X17AD, 0X1663, 0X13EE, 0X11C1, 0X0FD1,
//中音 1
0x0EF0, 0X0D4F, 0X0BDB, 0X0B31, 0X09F7, 0X08E1, 0X07E8,
//高音 2
0X1912, 0X06A6, 0X05ED, 0X0598, 0X04FC, 0X0470, 0X03F9};
//初始化函数声明
void Init_Sys(void)
{
CLKCONCMD &= ~0x7f; //晶振设置为32MHZ
while (CLKCONSTA & 0x40)
; //等待晶振稳定
P1SEL &= ~((1 << 0) | (1 << 1));
P1DIR |= (1 << 0) | (1 << 1);
P2SEL &= ~(1 << 0); // P2_0通用I/O
P2DIR |= (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比较模式模为125us
jiepai_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; //设置系统主时钟频率为32MHZ
SLEEPCMD |= 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; //获得最佳的EVM
RFIRQM0 |= (1 << 6); // RXPKTDONE 中断位使能
IEN2 |= (1 << 0); // RF 中断使能
EA = 1; //开中断
FREQCTRL = 0x0a; //信道选择,选择11信道
SHORT_ADDR0 = 0x05; // 0x0005 //目标地址过滤期间使用的短地址
SHORT_ADDR1 = 0x00;
PAN_ID0 = 0x23; // 0x0022 //目标地址过滤期间使用的PANID
PAN_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(); //初始化OLED
OLED_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;
// OLED
P0DIR |= 0x73;
OLED_Init(); //初始化OLED
OLED_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)