|
在两个普通LED间进行数据通讯的原理我就不说了,如果还有不知道的请搜索论坛上LED用做传感器的相关帖子。我使用的是两个高亮LED,通讯距离没有测过,我个人认为没有必要,视频里面的距离大概在8cm左右。这只是一个简单的演示,如果你采用的LED和我不一样,程序可能需要改变一些参数。
MEGA16上的代码:
//===============================================
// 两个LED间数据通讯
// =================
// 该代码在MEGA16上实现了通过一个普通LED接收数
//据包,并通过该LED发送应答包。代码重在描述普通LED
//间实现通讯的原理,并不能在任意种类的两个LED间进行
//数据通讯,如果要实现将任何一个LED作为一个通讯端口,
//就要采用自适应算法。这个技术应用得好的话,你就不
//需要为你的产品留通讯接口了,再也不需要为产品调试
//或设置参数预留接口了,再也不用拆机或连线了,一切
//都可以通过一个电源灯或指示灯完成于无形之中。
//
// 电路:PA0---[+LED-]---[R300]---PA1
//
//
// by:xingcn 点点星尘
// 2007.11.08
//===============================================
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <avr/interrupt.h>
#define TRUE 1
#define FALSE 0
#define SBIT(x,y) (x|=(1<<y))
#define CBIT(x,y) (x&=~(1<<y))
#define BIT(x,y) (x&(1<<y))
#define LED_ON(x) CBIT(PORTD, x)
#define LED_OFF(x) SBIT(PORTD, x)
#define B_9600 51
#define B_38400 12
#define LED_PORT PORTA
#define LED_DDR DDRA
#define LED_PIN PINA
#define LED_N PA0 //LED+
#define LED_P PA1 //LED-
#define LED_N_OUT() SBIT(LED_DDR, LED_N)
#define LED_P_OUT() SBIT(LED_DDR, LED_P)
#define LED_N_IN() CBIT(LED_DDR, LED_N)
#define LED_P_IN() CBIT(LED_DDR, LED_P)
#define LED_N_HIG() SBIT(LED_PORT, LED_N)
#define LED_N_LOW() CBIT(LED_PORT, LED_N)
#define LED_P_HIG() SBIT(LED_PORT, LED_P)
#define LED_P_LOW() CBIT(LED_PORT, LED_P)
#define PACK_SIZE 18
#define PB_FUNC(x) (x[0] >> 4)
#define PB_DATN(x) (x[0] & 0x0F)
//--------------------------------------------------------
void delay_ms(unsigned int);
void port_init(void);
void usart_init(unsigned int);
unsigned char led_light_recv(void);
unsigned char led_send_char(const unsigned char);
void led_send_pack(const char, const void *, const char);
//--------------------------------------------------------
unsigned char rs,rb,rn,ln,bn,ro,pack[PACK_SIZE],rb_event;
//--------------------------------------------------------
//===============================================
//名称:delay_ms
//功能:毫秒延时
//参数:unsigned int ms 要延时的毫秒数
//返回:无
//备注:无
//===============================================
void delay_ms(unsigned int ms)
{
unsigned int i=0x0000;
while(i < ms)
{
_delay_loop_2(10*25 *4);
i++;
}
}
//===============================================
//名称:usart_init
//功能:串口初始化
//参数:unsigned int baud 波特率
//返回:无
//备注:无
//===============================================
void usart_init(unsigned int baud)
{
UBRRH = (unsigned char)(baud >> 8);
UBRRL = (unsigned char)baud;
UCSRA = 0x02; //U2X = 1
UCSRB = (1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|0x06;
}
//===============================================
//名称:port_init
//功能:端口初始化
//参数:无
//返回:无
//备注:无
//===============================================
void port_init(void)
{
PORTA = 0xFF;
PORTB = 0xFF;
PORTC = 0xFF;
PORTD = 0xFF;
//做输入用
DDRA = 0x00;
DDRB = 0x00;
DDRC = 0x00;
DDRD = 0xFE;
cli();
}
//===============================================
//名称:led_light_recv
//功能:检测LED受光状态
//参数:无
//返回:光照达到给定亮度返回 TRUE
// 光照达不到给定亮度返回 FALSE
//备注:无
//===============================================
unsigned char led_light_recv(void)
{
unsigned char i;
LED_P_OUT();
LED_N_OUT();
LED_N_HIG();
LED_P_LOW();
delay_ms(1);
LED_N_LOW();
LED_P_HIG();
delay_ms(1);
LED_P_IN();
LED_P_LOW();
LED_N_LOW();
for(i = 0x00; i < 0x03; i++)
{
delay_ms(1);
if(!BIT(LED_PIN, LED_P))
return TRUE;
}
return FALSE;
}
//===============================================
//名称:led_send_char
//功能:通过LED发送一个字节
//参数:unsigned char c 要发送的字节
//返回:发送的字节
//备注:无
//===============================================
unsigned char led_send_char(const unsigned char c)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
LED_N_OUT();
LED_P_OUT();
LED_N_HIG();
LED_P_LOW();
if(BIT(c, ( 7 - i ))) // 高位在前
delay_ms(30);
else
delay_ms(15);
LED_N_LOW();
delay_ms(15);
}
return c;
}
//===============================================
//名称:led_send_pack
//功能:通过LED发送一个数据包
//参数:char c 功能号
// void *dat 数据
// char dn 数据量
//返回:无
//备注:数据包格式"功能号(高4位)|数据量(低4位)+
// 数据+(8bit)LRC校验",允许发送空数据。
//===============================================
void led_send_pack(const char func, const void *dat, const char dn)
{
unsigned char n,lrc = 0;
unsigned char *p = (unsigned char *)dat;
//发送接收识别头
LED_N_OUT();
LED_P_OUT();
LED_N_HIG();
LED_P_LOW();
delay_ms(60);
LED_N_LOW();
delay_ms(15);
//每个包最多发送16个字节
n = (func << 4) | ((p) ? (dn & 0x0F) : 0x00);
lrc += led_send_char(n);
for(n = 0; p != NULL && n < (dn & 0X0F); n++)
{
lrc += led_send_char(p[n]);
}
//发送校验字节
led_send_char(lrc);
}
//============================================
//名称:main
//功能:主函数
//参数:无
//返回:1
//备注:无
//============================================
int main(void)
{
unsigned char lrc,i;
port_init();
usart_init(B_9600);
ln = 0;
rb_event = FALSE;
for(;;)
{
rs = led_light_recv();
if(rs)
{
ln++;
}
else
{
if(ln >= 0x0F && ln <= 0x12)
{
bn = 0;
rb = 0;
ln = 0;
rn = 0;
ro = 0;
while(1)
{
rs = led_light_recv();
if(rs)
{
ln++;
}
else
{
if(ln >= 0x04 && ln <= 0x06) //收到0
{
rb <<= 1;
bn++;
ro = 0;
}
else if(ln >= 0x08 && ln <= 0x0A) //收到1
{
rb <<= 1;
rb++;
bn++;
ro = 0;
}
else //接收错误
{
if(++ro > 0x03)
break;
}
if(bn == 0x08) //收到一个字节
{
bn = 0;
pack[rn++] = rb;
rb = 0;
if(rn == PB_DATN(pack) + 2) //收到一个数据包
{
rb_event = TRUE;
break;
}
}
ln = 0;
}
}
}
ln = 0;
}
//事件处理
if(rb_event)
{
rb_event = FALSE;
lrc = 0;
for(i = 0; i < (PB_DATN(pack) + 1); i++)
lrc += pack;
if(lrc == pack)
{
if(PB_FUNC(pack) == 1)
{
for(i = 1; i < (PB_DATN(pack) + 1); i++) //将收到数据发送到PC
{
while( !(UCSRA & (1<<UDRE)) );
UDR = pack;
}
delay_ms(20);
led_send_pack(2,NULL,0); //发送接收成功应答包
}
}
}
}
return 1;
}
TINY13上的代码:
//===============================================
// 两个LED间数据通讯
// =================
// 该代码在TINY13实现了将数据以包的形式通过一个
//普通LED发送出去,并通过该LED接收数据。代码重在描
//述普通LED间实现通讯的原理,并不能在任意种类的两个
//LED间进行数据通讯,如果要实现将任何一个LED作为一
//个通讯端口,就要采用自适应算法。这个技术应用得好
//的话,你就不需要为你的产品留通讯接口了,再也不需
//要为产品调试或设置参数预留接口了,再也不用拆机或
//连线了,一切都可以通过一个电源灯或指示灯完成于无
//形之中。
//
// 电路:PB0---[+LED-]---[R300]---PB1
//
//
// by:xingcn 点点星尘
// 2007.11.08
//===============================================
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
//===============================================
#define TRUE 1
#define FALSE 0
#define SBIT(x,y) (x|=(1<<y))
#define CBIT(x,y) (x&=~(1<<y))
#define BIT(x,y) (x&(1<<y))
#define LED_ON(x) CBIT(PORTB, x)
#define LED_OFF(x) SBIT(PORTB, x)
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PINB
#define LED_N PB0 //LED+
#define LED_P PB1 //LED-
#define LED_N_OUT() SBIT(LED_DDR, LED_N)
#define LED_P_OUT() SBIT(LED_DDR, LED_P)
#define LED_N_IN() CBIT(LED_DDR, LED_N)
#define LED_P_IN() CBIT(LED_DDR, LED_P)
#define LED_N_HIG() SBIT(LED_PORT, LED_N)
#define LED_N_LOW() CBIT(LED_PORT, LED_N)
#define LED_P_HIG() SBIT(LED_PORT, LED_P)
#define LED_P_LOW() CBIT(LED_PORT, LED_P)
#define PACK_SIZE 18
#define PB_FUNC(x) (x[0] >> 4)
#define PB_DATN(x) (x[0] & 0x0F)
//===============================================
void delay_ms(unsigned int);
unsigned char led_light_recv(void);
unsigned char led_send_char(const unsigned char);
void led_send_pack(const char, const void *, const char);
//--------------------------------------------
unsigned char rb,rn,ln,bn,ro,rs,pack[PACK_SIZE],rb_event;
//============================================
//名称:delay_ms
//功能:毫秒延时
//参数:unsigned int ms 要延时的毫秒数
//返回:无
//备注:无
//============================================
void delay_ms(unsigned int ms)
{
unsigned int i=0;
while(i < ms)
{
_delay_loop_2(240);
i++;
}
}
//===============================================
//名称:led_light_recv
//功能:检测LED受光状态
//参数:无
//返回:光照达到给定亮度返回 TRUE
// 光照达不到给定亮度返回 FALSE
//备注:无
//===============================================
unsigned char led_light_recv(void)
{
unsigned char i;
LED_P_OUT();
LED_N_OUT();
LED_N_HIG();
LED_P_LOW();
delay_ms(1);
LED_N_LOW();
LED_P_HIG();
delay_ms(1);
LED_P_IN();
LED_P_LOW();
LED_N_LOW();
for(i = 0x00; i < 0x03; i++)
{
delay_ms(1);
if(!BIT(LED_PIN, LED_P))
return TRUE;
}
return FALSE;
}
//===============================================
//名称:led_send_char
//功能:通过LED发送一个字节
//参数:unsigned char c 要发送的字节
//返回:发送的字节
//备注:无
//===============================================
unsigned char led_send_char(const unsigned char c)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
LED_N_OUT();
LED_P_OUT();
LED_N_HIG();
LED_P_LOW();
if(BIT(c, ( 7 - i ))) // 高位在前
delay_ms(30);
else
delay_ms(15);
LED_N_LOW();
delay_ms(15);
}
return c;
}
//===============================================
//名称:led_send_pack
//功能:通过LED发送一个数据包
//参数:char c 功能号
// void *dat 数据
// char dn 数据量
//返回:无
//备注:数据包格式"功能号(高4位)|数据量(低4位)+
// 数据+(8bit)LRC校验",允许发送空数据。
//===============================================
void led_send_pack(const char func, const void *dat, const char dn)
{
unsigned char n,lrc = 0;
unsigned char *p = (unsigned char *)dat;
//发送接收识别头
LED_N_OUT();
LED_P_OUT();
LED_N_HIG();
LED_P_LOW();
delay_ms(60);
LED_N_LOW();
delay_ms(15);
//每个包最多发送16个字节
n = (func << 4) | ((p) ? (dn & 0x0F) : 0x00);
lrc += led_send_char(n);
for(n = 0; p != NULL && n < (dn & 0X0F); n++)
{
lrc += led_send_char(p[n]);
}
//发送校验字节
led_send_char(lrc);
}
//============================================
//名称:main
//功能:主函数
//参数:无
//返回:1
//备注:无
//============================================
int main(void)
{
unsigned char lrc,i;
SBIT(PORTB, PB2);
SBIT(DDRB, PB2);
SBIT(PORTB, PB3);
SBIT(DDRB, PB3);
ln = 0;
rb_event = FALSE;
for(;;)
{
//数据接收
rs = led_light_recv();
if(rs)
{
ln++;
}
else
{
if(ln >= 0x19 && ln <= 0x1C)
{
bn = 0;
rb = 0;
ln = 0;
rn = 0;
ro = 0;
while(1)
{
rs = led_light_recv();
if(rs)
{
ln++;
}
else
{
if(ln >= 0x06 && ln <= 0x09)
{
rb <<= 1;
bn++;
ro = 0;
}
else if(ln >= 0x0D && ln <= 0x10)
{
rb <<= 1;
rb++;
bn++;
ro = 0;
}
else
{
if(++ro > 0x03)
break;
}
if(bn == 0x08) //接收到一个字节
{
bn = 0;
pack[rn++] = rb;
rb = 0;
if(rn == PB_DATN(pack) + 2)
{
rb_event = TRUE;
break;
}
}
ln = 0;
}
}
}
ln = 0;
}
//事件处理
if(rb_event)
{
rb_event = FALSE;
lrc = 0;
for(i = 0; i < (PB_DATN(pack) + 1); i++)
lrc += pack;
if(lrc == pack)
{
if(PB_FUNC(pack) == 2)
{
//点亮指示LED,表示收到正确数据包
LED_ON(PB3);
delay_ms(50);
LED_OFF(PB3);
}
}
}
//按键发送
if(!BIT(PINB, PB2))
{
delay_ms(10);
if(!BIT(PINB, PB2))
{
strcpy((char *)&pack[1], "www.ouravr.com\n");
led_send_pack(1, &pack[1], strlen((char *)&pack[1]));
}
}
}
return 1;
}
演示视频:
普通LED用于指示和数据通讯(视频)(文件大小:9.32M) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|