CC2500无线模块可以做无线鼠标,提供全套AVR程序和硬件图
2.4G无线数据模块(CC2500芯片)
频率范围:2400-2483.5Mhz (90信道)
最大速率:500K
调制方式:MSK,QPSK在500Kbps, GFSK ,OOK在250kbps
RF输出功率:0dBm
灵敏度: -101dBm在10Kbps 1%
编程接口:SPI数字接口
电压:1.8-3.6V
最大功耗:20mA
封装形式:COB
模块尺寸:11 X 15 X 8mm (长X宽X高)
天线形式:PCB天线
最大距离:100米
应用范围:工业数据传输,无线遥控,无线鼠标,无线键盘,无线电子标签,遥控玩具,自动化数据采集系统;工业无线控制;水、气、热、电等居民计量表具无线远传自动抄表
无线鼠标接收程序:
//接收端程序,内部振荡器,8Mhz #include <iom8v.h> #include <macros.h>
#define uint unsigned int #define uchar unsigned char #define h_clk_read DDRD&=~0x08 #define h_clk_ctrl DDRD|= 0x08 #define h_data_read DDRD&=~0x04 #define h_data_ctrl DDRD|= 0x04 #define h_clk_high PORTD|=0x08 #define h_clk_low PORTD&=~0x08 #define h_data_high PORTD|=0x04 #define h_data_low PORTD&=~0x04 //以上定义host端clk与data针脚的输入输出,高低电平 #define CSn_on PORTD|=0x20 #define CSn_off PORTD&=~0x20 #define sclk_on PORTD|=0x80 #define sclk_off PORTD&=~0x80 #define si_on PORTB|=0x01 #define si_off PORTB&=~0x01 #define so_read DDRD&=~0x40 //以上定义CC2500片选和spi针脚各状态 #define burst 0x40 #define read_reg 0x80 #define write_reg 0x00 #define sres 0x30 #define scal 0x33 #define srx 0x34 #define stx 0x35 #define sfrx 0x3a #define sidle 0x36 //以上定义CC2500有关指令 uchar ps2update; uchar tt; uchar sample_rate,resolution,command; uchar frommouse[6]; uchar reply_to_host[4]; void delay(uint tt) {while(tt--);} void timer2_init(void) { TCCR2 = 0x00; //stop ASSR = 0x00; TCNT2 = 0x00; TIMSK = 0x80;//interrupt sourse OCR2 = 50; //interval parameter }
#pragma interrupt_handler timer2_comp_isr:4 //设置PS2协议传输的时间间距 void timer2_comp_isr(void) {uchar temp; TCNT2 = 0x00; temp=~PORTD; PORTD|=temp&0x08;PORTD&=temp|0xf7; ps2update++; }
uchar sendbyte_to_host(unsigned char bitpointer) //发字节到主机子程序 {uchar i,temp,parity; ps2update=parity=0; h_clk_read;h_clk_high;h_data_read;h_data_high;NOP();NOP(); while(!(PIND&0x08)) { while(!(PIND&0x08))NOP(); delay(50);} h_clk_ctrl;h_data_ctrl;h_data_low;NOP();// send start bit h_clk_low; SEI();TCCR2 = 0x0A; //start,prescale=8,CTC mode while(ps2update!=1);ps2update=0;delay(10); for(i=0;i!=8;i++) {temp=(bitpointer>>i)<<2; if(temp&0x04)parity++; PORTD|=temp&0x04; PORTD&=temp|0xfb; h_clk_read; while(ps2update!=1) { if(!(PIND&0x08)){TCCR2=0x00;CLI();TCNT2=0x00;h_data_high;return 0;} } ps2update=0;h_clk_ctrl; while(ps2update!=1);ps2update=0;delay(10); } if(parity%2==0) h_data_high;//send parity bit else h_data_low; h_clk_read; while(ps2update!=1) { if(!(PIND&0x08)){TCCR2=0x00;CLI();TCNT2=0x00;h_data_high;return 0;} } ps2update=0;h_clk_ctrl; while(ps2update!=1);ps2update=0;delay(10); h_data_high; while(ps2update!=2);ps2update=0;delay(10); // stop bit TCCR2=0x00; CLI();TCNT2 = 0x00; //stop timer h_clk_read;NOP();NOP();//wait for release clock for(i=0;i!=5;i++) {if(!(PIND&0x08))i=0;delay(50);} return 1; }
uchar read_command(void) //从主机读命令 {uchar i,temp;uchar return_cmd=0; h_data_read;h_data_high; h_clk_read;h_clk_high;delay(3); for(i=0;i!=51;i++) {while(!(PIND&0x08));//wait for release clock if(PIND&0x04)i=0;//wait for data be low } while(!(PIND&0x08));delay(5); h_clk_ctrl;
ps2update=0;temp=0;delay(3); SEI();TCCR2 = 0x0A; //start,prescale=8,CTC mode for(i=0;i!=8;i++) {while(ps2update!=2);ps2update=0;delay(5); temp=PIND&0x04; return_cmd|=(temp>>2)<<i; } while(ps2update!=2);ps2update=0;delay(5);//get parity while(ps2update!=2);ps2update=0;delay(20);//get stop h_data_ctrl;h_data_low;//ack while(ps2update!=2);ps2update=0; TCCR2=0x00; CLI(); TCNT2 = 0x00;delay(50);//stop timer h_data_high;delay(10); h_clk_read;delay(3);//wait for release clock for(i=0;i!=100;i++) {if(!(PIND&0x08)){i=0;delay(6);} delay(6); } return return_cmd; }
uchar SPI_command(unsigned char bitpointer) //发指令到CC2500 {uchar i,temp_SI,temp_SO,return_SO; i=temp_SI=temp_SO=return_SO=0; sclk_off;NOP();NOP();NOP(); CSn_off;NOP();NOP();//CSn low while(PIND&0x40); // wait until SO low for(i=0;i!=8;i++) { NOP();NOP();NOP();NOP();NOP();NOP(); temp_SI=(bitpointer>>(7-i)); PORTB|=temp_SI&0x01; PORTB&=temp_SI|0xfe; PORTD|=0x80; NOP();NOP();NOP(); temp_SO=PIND&0x40; return_SO|=((temp_SO<<1)>>i); NOP();NOP();NOP();NOP();NOP();NOP(); sclk_off; } if((!bitpointer&0x40)) // bitpointer is a cmmd,set CSn & SCLK high {CSn_on;NOP();NOP();NOP(); sclk_on; } return return_SO; }
void SPI_host_send(unsigned char bitpointer) //写字节到CC2500,功能兼容SPI_command {uchar i,temp_SI; i=temp_SI=0; sclk_off;NOP();NOP();NOP(); CSn_off;NOP();NOP();//CSn low while(PIND&0x40);delay(3); // wait until SO low for(i=0;i!=8;i++) {NOP();NOP();NOP();NOP();NOP();NOP(); temp_SI=(bitpointer>>(7-i)); PORTB|=temp_SI&0x01; PORTB&=temp_SI|0xfe; sclk_on; NOP();NOP();NOP();NOP();NOP();NOP(); sclk_off; } } uchar SPI_host_read(void) //读字节从CC2500 {uchar i,temp_SO,return_SO; i=temp_SO=return_SO=0; for(i=0;i!=8;i++) { sclk_on;NOP();NOP();NOP(); temp_SO=PIND&0x40; return_SO|=((temp_SO<<1)>>i); NOP();NOP();NOP();NOP();NOP();NOP(); sclk_off; NOP();NOP();NOP();NOP();NOP();NOP(); } return return_SO; } void cc2500_RX_initialization(void) //CC2500初始化 {uchar read; SPI_host_send(sres);delay(1000); SPI_host_send(scal);delay(1000); SPI_host_send(0x00);SPI_host_send(0x07); SPI_host_send(0x06);SPI_host_send(0x06);//fixed packet length =6 SPI_host_send(0x07);SPI_host_send(0x84); SPI_host_send(0x08);SPI_host_send(0x0c); SPI_host_send(0x0b);SPI_host_send(0x09); SPI_host_send(0x0d+burst+write_reg); SPI_host_send(0x5d); SPI_host_send(0xb1); SPI_host_send(0x38); SPI_host_send(0x3d); SPI_host_send(0x3b); SPI_host_send(0x73); SPI_host_send(0xa2); SPI_host_send(0xf8); SPI_host_send(0x01); SPI_host_send(0x07); SPI_host_send(0x30); SPI_host_send(0x18); SPI_host_send(0x1d); SPI_host_send(0x1c); SPI_host_send(0xc7); SPI_host_send(0x00); SPI_host_send(0xb2); CSn_on;NOP();NOP();NOP();NOP();NOP();NOP(); SPI_host_send(0x21);SPI_host_send(0xb6); SPI_host_send(0x23);SPI_host_send(0xca); SPI_host_send(0x26);SPI_host_send(0x11); calibrate: read=SPI_command(sfrx);//sfrx SPI_host_send(scal);delay(690); SPI_host_send(0x25+read_reg);read=SPI_host_read(); while(read==0x3f){SPI_host_send(0x25+read_reg);read=SPI_host_read();} } void main(void) {uchar i,j,readcc2500,buffer; OSCCAL=0xa9; PORTB=0xff;PORTD=0xff; DDRB=0x01;DDRD=0xb0; delay(600); MCUCR = 0x00; GICR = 0x00; TIMSK = 0x00; delay(51000); cc2500_RX_initialization(); timer2_init(); sample_rate=100;resolution=0x03; ps2update=0; finish_init: SPI_command(sfrx); SPI_command(srx); while(9) { SPI_host_send(0xf5);readcc2500=SPI_host_read(); //循环检测CC2500有无接收到数据 if(readcc2500==0x01)//check whether CRC ok { SPI_host_send(0xff); for(tt=0;tt!=6;tt++) {frommouse[tt]=SPI_host_read();} CSn_on;NOP();NOP();NOP();sclk_on;NOP();NOP();NOP(); if((frommouse[0]==0xbb)&&(frommouse[1]==0xaa)) //模拟地址过滤 {for(tt=2;tt!=6;tt++) {to_host: //把无线鼠标的相关字节发回电脑 buffer=sendbyte_to_host(frommouse[tt]); if(buffer==0) {while(!(PIND&0x08)) { while(!(PIND&0x08))NOP(); delay(50);}//每次发字节到主机后都要检测主机有无拉低CLK中止传输 h_data_read;h_data_high;NOP();NOP(); if(!(PIND&0x04))break; else goto to_host; } } } h_data_read;h_data_high;NOP();NOP();NOP(); if(!(PIND&0x04)){SPI_command(sidle);break;} //睡眠CC2500 SPI_command(sfrx); SPI_command(srx); } h_data_read;h_data_high;NOP();NOP();NOP(); if(!(PIND&0x04)){SPI_command(sidle);break;} }
command=read_command(); //从主机接收命令并处理 initialization: switch(command) {case 0xff:reply_to_host[0]=0xfa;reply_to_host[1]=0xaa;//reset reply_to_host[2]=0x00;j=3;break;//pass case 0xf6:reply_to_host[0]=0xfa;j=1;break;//set default case 0xf5:reply_to_host[0]=0xfa;j=1;break;//disable report case 0xf2:reply_to_host[0]=0xfa;reply_to_host[1]=0x03;j=2;break;//get ID case 0xea:reply_to_host[0]=0xfa;j=1;break;//set stream mode case 0xe6:reply_to_host[0]=0xfa;j=1;break;//scaling 1:1 case 0xe7:reply_to_host[0]=0xfa;j=1;break;//scaling 2:1 case 0xe9:reply_to_host[0]=0xfa;reply_to_host[1]=0x00;//status request reply_to_host[2]=resolution; reply_to_host[3]=sample_rate;j=4;break; case 0xe8:buffer=sendbyte_to_host(0xfa); //set resolution resolution=read_command();reply_to_host[0]=0xfa;j=1;break; case 0xf3:buffer=sendbyte_to_host(0xfa); //set sample rate sample_rate=read_command();reply_to_host[0]=0xfa;j=1;break; case 0xf4:buffer=sendbyte_to_host(0xfa);goto finish_init; //set resolution } for(i=0;i!=j;i++) {h_clk_read;h_clk_high;h_data_read;h_data_high;delay(3); while(!(PIND&0x08)); if(!(PIND&0x04))break; else buffer=sendbyte_to_host(reply_to_host); } command=read_command(); goto initialization; }
无线鼠标发送程序:
//transmitter //crystal = 4.0Mhz //NO movement in 327s then M8 turns off mouse&CC2500 & goes to power-down mode,resulting in 0.2ma consumption //every time CC2500 finishes transmitting,it will be forced to goto SLEEP mode //NO movement in 2s, M8 goes to IDLE state,consumption decreases from 7.23ma down to 4.48ma //watch dog timer:WDTCR = 0x0D,512K pulses,about 0.52s #include <iom8v.h> #include <macros.h>
#define uint unsigned int #define uchar unsigned char #define m_clk_read DDRD&=~0x08 #define m_clk_ctrl DDRD|= 0x08 #define m_data_read DDRC&=~0x01 #define m_data_ctrl DDRC|= 0x01 #define m_clk_high PORTD|=0x08 #define m_clk_low PORTD&=~0x08 #define m_data_high PORTC|=0x01 #define m_data_low PORTC&=~0x01 #define mouse_on PORTD&=~0x10 #define mouse_off PORTD|=0x10 //以上定义PS2鼠标的CLK,DATA针脚的输入输出,高低电平和开,关鼠标电源 #define CSn_on PORTD|=0x20 #define CSn_off PORTD&=~0x20 #define sclk_on PORTD|=0x80 #define sclk_off PORTD&=~0x80 #define si_on PORTB|=0x01 #define si_off PORTB&=~0x01 #define so_read DDRD&=~0x40 //以上定义cc2500有关的spi协议的针脚 #define burst 0x40 #define read_reg 0x80 #define write_reg 0x00 #define scal 0x33 #define srx 0x34 #define stx 0x35 #define sftx 0x3b #define spwd 0x39 #define sxoff 0x32 #define snop 0x3d //以上定义cc2500有关的指令 #define cc2500_on PORTB&=~0x80 #define cc2500_off PORTB|=0x80 //以上定义cc2500的电源开关 #define enable_int0 GICR |=0x40 #define disable_int0 GICR &=~0x40 #define enable_int1 GICR |=0x80 #define disable_int1 GICR &=~0x80 #define enable_powerdown MCUCR |=0xa0 #define disable_powerdown MCUCR &=~0xa0 #define enable_idle MCUCR |=0x80 #define disable_idle MCUCR &=~0x80 #define wdt_off WDTCR = (1<<WDCE)|(1<<WDE);WDTCR =0x00 uint sleeptime; uchar tt,gotosleep; uchar sample_rate,resolution,command; uchar frommouse[6];
void delay(uint tt) {while(tt--);}
void timer0_init(void) //定义睡眠定时器 { TCCR0 = 0x00; //stop TCNT0 = 0x00; //set count TIMSK |= 0x01; //interrupt sourse TCCR0 = 0x05; //start timer } #pragma interrupt_handler timer0_ovf_isr:10 void timer0_ovf_isr(void) {TCNT0 = 0x00; sleeptime++; if(sleeptime==5000)gotosleep=1; //about 327 seconds } #pragma interrupt_handler int0_isr:2 //定义掉电睡眠的外中断唤醒服务程序 void int0_isr(void) {delay(500); TCCR0 = 0x05;disable_int0;disable_powerdown; PORTD=0xec;PORTB=0xff;PORTC=0xff; DDRB=0x81;DDRD=0xb0;DDRC=0x00; mouse_on;cc2500_on;WDTCR = 0x0D; //使用看门狗 } #pragma interrupt_handler int1_isr:3 //定义待机睡眠的外中断唤醒服务程序 void int1_isr(void) { disable_int1;disable_idle;WDTCR = 0x0D; }
uchar read_from_mouse(void) //定义从鼠标读字节子程 {uchar i,temp; uchar receive=0; m_clk_high;m_data_high; m_clk_read;m_data_read;//NOP();NOP(); WDR(); while(PIND&0x08); //wait start bit if(PINC&0x01)while(9); //if start bit is faulty,wait for watchdog to reset while(!(PIND&0x08)); NOP(); for(i=0;i!=8;i++) {while(PIND&0x08); temp=PINC&0x01;receive|=temp<<i; NOP(); while(!(PIND&0x08));WDR(); NOP(); } while(PIND&0x08); //wait parity bit NOP(); while(!(PIND&0x08)); NOP(); while(PIND&0x08);NOP(); //wait stop bit while(!(PIND&0x08));NOP(); WDR(); return receive; } void send_a_command(uchar command) //定义发命令到鼠标子程 {uchar i,temp,parity; parity=0; WDR(); m_clk_ctrl;m_data_ctrl;NOP();NOP();m_clk_low;//pull clock low delay(20); m_data_low;delay(20); //pull data low m_clk_high;m_clk_read; //release clock for(i=0;i!=8;i++) {while(PIND&0x08);NOP(); temp=command>>i; if(temp&0x01)parity++; PORTC|=temp&0x01; PORTC&=temp|0xfe; while(!(PIND&0x08));NOP();WDR(); } while((PIND&0x08));NOP(); if(parity%2==0) m_data_high; else m_data_low; //send parity bit while(!(PIND&0x08));NOP(); while((PIND&0x08));NOP(); m_data_high; //send stop bit while(!(PIND&0x08));WDR(); m_data_read;NOP();NOP(); while(PIND&0x08);NOP(); //wait ack while(!(PIND&0x08)); WDR(); } void connectmouse_init(void) //定义鼠标初始化 {uchar i,buffer,counter; WDR(); send_a_command(0xff);buffer=read_from_mouse(); //reset buffer=read_from_mouse();buffer=read_from_mouse();WDR(); send_a_command(0xf2);buffer=read_from_mouse();buffer=read_from_mouse();//get ID send_a_command(0xf3);buffer=read_from_mouse(); //set sample send_a_command(200); buffer=read_from_mouse(); //sample rate =200 send_a_command(0xf3);buffer=read_from_mouse(); //set sample rate send_a_command(0x64);buffer=read_from_mouse(); //sample rate =100 send_a_command(0xf3);buffer=read_from_mouse(); //set sample send_a_command(0x50);buffer=read_from_mouse(); //sample rate =80 send_a_command(0xf2);buffer=read_from_mouse();buffer=read_from_mouse();//get ID send_a_command(0xf3);buffer=read_from_mouse(); //set sample rate send_a_command(100); buffer=read_from_mouse(); //sample rate =100 send_a_command(0xe8);buffer=read_from_mouse(); //set resolution send_a_command(0x02);buffer=read_from_mouse(); //resolution = 4 counts/mm send_a_command(0xe6);buffer=read_from_mouse(); //set scaling 1:1 send_a_command(0xf4);buffer=read_from_mouse(); //enable data reporting } uchar SPI_command(unsigned char bitpointer) //发指令到CC2500 {uchar i,temp_SI,temp_SO,return_SO; i=temp_SI=temp_SO=return_SO=0; WDR(); sclk_off;NOP(); CSn_off;NOP(); //CSn low while(PIND&0x40); // wait until SO low for(i=0;i!=8;i++) { NOP(); temp_SI=(bitpointer>>(7-i)); PORTB|=temp_SI&0x01; PORTB&=temp_SI|0xfe; PORTD|=0x80;NOP(); temp_SO=PIND&0x40; return_SO|=((temp_SO<<1)>>i); NOP(); sclk_off; } if(!(bitpointer&0x40)) // bitpointer is a cmmd,set CSn & SCLK high {CSn_on;NOP(); sclk_on;NOP(); } WDR(); return return_SO; } void SPI_host_send(unsigned char bitpointer) //写字节到CC2500,功能兼容SPI_command {uchar i,temp_SI; i=temp_SI=0; WDR(); sclk_off;NOP(); CSn_off;NOP(); //CSn low while(PIND&0x40);NOP(); // wait until SO low for(i=0;i!=8;i++) {NOP(); temp_SI=(bitpointer>>(7-i)); PORTB|=temp_SI&0x01; PORTB&=temp_SI|0xfe; sclk_on; NOP(); sclk_off; } WDR(); } uchar SPI_host_read(void) //读字节从CC2500 {uchar i,temp_SO,return_SO; i=temp_SO=return_SO=0; WDR(); for(i=0;i!=8;i++) { sclk_on;NOP(); temp_SO=PIND&0x40; return_SO|=((temp_SO<<1)>>i); NOP(); sclk_off; NOP(); } WDR(); return return_SO; } void cc2500_TX_initialization(void) //初始化cc2500 {uchar read; SPI_host_send(scal);delay(130); SPI_host_send(0x01);SPI_host_send(0x07); SPI_host_send(0x06);SPI_host_send(0x06); //fixed packet length =6 SPI_host_send(0x08);SPI_host_send(0x0c); SPI_host_send(0x0b);SPI_host_send(0x09); SPI_host_send(0x0d+burst+write_reg); SPI_host_send(0x5d); SPI_host_send(0xb1); SPI_host_send(0x38); SPI_host_send(0x2d); SPI_host_send(0x3b); SPI_host_send(0x73); SPI_host_send(0xd2); SPI_host_send(0xf8); SPI_host_send(0x01); SPI_host_send(0x07); SPI_host_send(0x30); SPI_host_send(0x18); SPI_host_send(0x1d); SPI_host_send(0x1c); SPI_host_send(0xc7); SPI_host_send(0x00); SPI_host_send(0xb2); CSn_on;NOP(); SPI_host_send(0x21);SPI_host_send(0xb6); SPI_host_send(0x23);SPI_host_send(0xca); SPI_host_send(0x26);SPI_host_send(0x11); SPI_command(sftx); SPI_host_send(scal);delay(85); SPI_host_send(0x25+read_reg);read=SPI_host_read(); while(read==0x3f){SPI_host_send(0x25+read_reg);read=SPI_host_read();} SPI_command(spwd); }
void main(void) {uchar readcc2500,i,j; OSCCAL=0x9f; PORTD=0xec;PORTB=0x7f;PORTC=0xff; DDRB=0x81;DDRD=0xb0;DDRC=0x00; CLI(); MCUCR = 0x00; GICR = 0x00; TIMSK = 0x00; delay(25);frommouse[0]=0xbb;frommouse[1]=0xaa; timer0_init();//for(i=2;i!=6;i++)frommouse=0x00; cc2500_TX_initialization(); sample_rate=100;resolution=0x03; sleeptime=0x00;gotosleep=0x00; for(i=0;i!=21;i++){delay(33000);} connectmouse_init(); WDR();SEI();WDTCR = 0x0D; //开看门狗 while(9) {startloop: m_clk_high;m_clk_read;NOP();NOP(); if(!(PIND&0x08)) { for(tt=2;tt!=6;tt++) {frommouse[tt]=read_from_mouse();} //从鼠标读字节 if((!(frommouse[2]&0x08))||(frommouse[2]&0xc0))//check bit3,6,7 of 1st byte {while(9);} m_clk_ctrl;m_clk_low; //inhibit mouse transmit sleeptime=0;WDR(); SPI_host_send(0x7f); //burst write TXfifo for(tt=0;tt!=6;tt++) {SPI_host_send(frommouse[tt]);} //写字节到CC2500 CSn_on;NOP(); //end burst write SPI_command(stx);delay(100); //go to TXmode SPI_host_send(0xf5);readcc2500=SPI_host_read();//check whether TX finished while(readcc2500!=0x01){SPI_host_send(0xf5);readcc2500=SPI_host_read();} SPI_command(spwd); //go into SLEEP mode,TXfifo lose value WDR();delay(300); m_clk_high;m_clk_read;NOP(); //release mouse tansmit } WDR(); if((gotosleep)&&(sleeptime>=5000)) //掉电睡眠定时器满足,进入掉电睡眠 {gotosleep=0;sleeptime=0;TCCR0 = 0x00;TCNT0 = 0x00; enable_int0; DDRD=0x10;DDRC=DDRB=0x00;PORTD=PORTB=PORTC=0xff;mouse_off;cc2500_off; enable_powerdown;CLI();wdt_off;SEI();SLEEP(); } if(sleeptime>30)//1.96seconds //待机睡眠定时满足,进入待机睡眠 {m_clk_high;m_clk_read;NOP(); enable_int1;enable_idle;CLI();wdt_off;SEI();SLEEP(); } } }
相关链接:http://auction1.taobao.com/auction/item_detail-0db2-a87459b7ea2395a73e67d17c283b2e32.jhtml |
|