|
#include "stdio.h"
#include "avr/io.h"
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
// 测量高电平脉冲长度,单位是微秒(uS),接收机输出脉冲宽度是1000uS - 2000uS,中点是1500uS
unsigned long pulseIn()
{
unsigned long width = 0;
unsigned long numloops = 0;
unsigned long timeout = 20000; // 超时设置为20ms
// 把超时转换为循环次数
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// 如果上一个脉冲没结束,则等待其结束
while( (PINB & _BV(PB0)) == _BV(PB0) )
if (numloops++ == maxloops)
return 0;
// 等待脉冲开始
while( (PINB & _BV(PB0)) == 0 )
if (numloops++ == maxloops)
return 0;
// 等待脉冲结束
while( (PINB & _BV(PB0)) == _BV(PB0) )
{
if (numloops++ == maxloops)
return 0;
width++;
}
// 把width转换成微秒
return clockCyclesToMicroseconds(width * 21 + 16);
}
// 脉冲宽度小于1200,认为是位置1
// 脉冲宽度小于1700,认为是位置2
// 其他情况认为是位置3
#define POSITION1 1200
#define POSITION2 1700
int main()
{
uint8_t pos;
uint8_t do_switch = 0;
uint8_t pin1_state = 0;
uint8_t pin2_state = 0;
// 启动时把PB1 PB2设置为低电平
cbi(PORTB, PB1);
cbi(PORTB, PB2);
// 配置PB0为输入 PB1,PB2为输出
DDRB = 6;
uint16_t delay_count = 30000; // 主频9.6M时,大约0.5秒延时的计数值
for(;;)
{
// 检测 3位开关通道 状态
unsigned long len = pulseIn();
if(len!=0)
{
if(len < POSITION1) pos = 1; // 3位开关通道 向上拨
else if(len < POSITION2) pos = 2; // 3位开关通道 回中位
else pos = 3; // 3位开关通道 向下拨
}
if(pos==3)
{
// 3位开关通道 向下拨 的状态,在PB2口输出脉冲 1次/秒
delay_count--;
if(delay_count==0)
{
if(pin2_state==0) cbi(PORTB, PB2);
else sbi(PORTB, PB2);
pin2_state = !pin2_state;
delay_count = 30000;
}
}
else{
// 其他状态一律把PB2口输出低电平
cbi(PORTB, PB2);
if(pos==1)
{
// 3位开关通道 回中后再向上拨一次 PB1口切换输出状态一次
if( do_switch==1 )
{
if(pin1_state==0) cbi(PORTB, PB1);
else sbi(PORTB, PB1);
pin1_state = !pin1_state;
do_switch = 0;
}
}
else do_switch = 1; // 3位开关通道 回中,设置标记,使下一次向上拨时可以切换状态
}
}
return 0;
}
|
|