📄 main.c
字号:
/************************************
* 6通道航模遥控器初级版ICC程序 *
* 功 能:6通道比例遥控PPM编码 *
* 电 路:6_RC_ZJ.SCH *
* 建立日期:2010年05月17日 *
* 版 本:V10.01 *
* 设 计 者:周长洪 *
* 修改日期:2010年05月17日 *
* 主控芯片:Mega16L-8AU *
* 时钟频率:外部8.0000Mhz *
* 编译系统:ICCAVR6.31A *
************************************/
#include <iom16v.h>
#include <macros.h>
#include "delay.h"
//简化数据类型定义
#define uchar unsigned char
#define uint unsigned int
//端口和数据宏定义
//PPM输出端口定义
#define PPM_CLR PORTD &= ~(1<<5)
#define PPM_SET PORTD |= 1<<5
#define PPM_TG PORTD ^= 1<<5
//蜂鸣器端口定义
#define SPK_CLR PORTD &= ~(1<<4)
#define SPK_SET PORTD |= 1<<4
#define SPK_TG PORTD ^= 1<<4
//LED灯端口定义
#define LED_OFF PORTA &= ~(1<<7)
#define LED_ON PORTA |= 1<<7
#define LED_TG PORTA ^= 1<<7
//常用参数定义
#define zhd 580 //定义定时修正参数
#define fxsj 2183 //定义反向数据参数
#define sysc 20 //定义微调时响声时长ms
#define sysc1 100 //定义微调中点响声时长
#define sysc2 400 //定义微调端点响声时长
#define dy1 505 //定义电压保护1:7.4V
#define dy2 477 //定义电压保护2:7.0V
#define wtcs 4 //定义微调步进长度
//数据定义
uint ch_ad[6]; //定义通道数据
uint ch_sj[6]; //定义ADC数据
uint dy_sj=1000; //定义电压数据
uint ch_wt[4]; //定义1-4通道中点数据
uchar flag = 0; //定义通道号
uchar ch_fx = 0; //定义通道反向数据
uchar a=0; //普通数据
/****************************
* 端口初始化 *
****************************/
void port_init(void)
{
PORTA = 0x00;
DDRA = 0x80; //A口除PA7外,为ADC输入
PORTB = 0xFF;
DDRB = 0x00; //B口为电子微调输入,上拉
PORTC = 0xFF;
DDRC = 0x00; //C口为通道正反向、混控输入
PORTD = 0x00;
DDRD = 0xFF; //D口为输出
}
/****************************
* 蜂鸣器函数 *
****************************/
void spk(uchar k,uint time)
{
for(;k;k--)
{
SPK_SET;
delay_ms(time);
SPK_CLR;
delay_ms(50);
}
}
/********************************
* EEPROM读取函数一 *
* 功能描述:读取1-4微调数据 *
* 入 口:无 *
* 返 回 值:无 *
* 固定地址:0-7 八字节 *
********************************/
void ee_read(void)
{
uchar da[8];
uchar k;
for(k=0;k<8;k++)
{
while(EECR & (1 << EEWE));
EEARH = 0;
EEARL = k; //读出地址高字节数据的位置
EECR |= (1 << EERE); //启动读数据
da[k] = EEDR; //读出数据
}
for(k=0;k<4;k++) //合成数据
{
ch_wt[k] = (da[2*k+1]<<8)+da[2*k];
}
}
/********************************
* EEPROM写入函数一 *
* 功能描述:写入1-4微调数据 *
* 入 口:需写入的数据和位置 *
* 返 回 值:无 *
* 固定地址:0-7 八字节 *
********************************/
void ee_write(uint da,uchar n)
{
EEARH = 0;
EEARL = 2*n; //写入地址数据的位置
EEDR = da & 0xFF; //需写入的数据低字节
EECR |= (1 << EEMWE);
EECR |= (1 << EEWE); //启动写入
delay_ms(10); //延时等待
EEARH = 0;
EEARL = 2*n+1; //写入地址数据的位置
EEDR = da >> 8; //需写入的数据高字节
EECR |= (1 << EEMWE);
EECR |= (1 << EEWE); //启动写入
delay_ms(10); //延时等待
}
/****************************
* AD转换函数 *
****************************/
uint ADC_Convert(void)
{
uint temp1,temp2;
temp1=ADCL;
temp2=ADCH;
temp2=(temp2<<8)+temp1;
return(temp2);
}
/****************************
* AD初始化函数 *
****************************/
void adc_init(void)
{
ADMUX=0x40; //选择第0通道ADC;V为基准
ADCSRA=0xE7; //125K转换速率,自由转换模式;启动AD转换器;
SFIOR = 0x00;
delay_ms(200); //延时等待系统稳定
}
/****************************
* TC0初始化函数 *
* 功 能:产生20mS帧周期 *
* 预 分 频:1024 *
* 工作模式:比较匹配中断 *
* 时钟频率:外部8.0000Mhz *
****************************/
void timer0_init(void)
{
TCCR0 = 0x00;
TCNT0 = 0x63;
TCCR0 = 0x05;
}
/****************************
* TC0中断入口函数 *
****************************/
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0 = 0x63; //重装初值
TCNT1H = 0x00; //装TC1初值:产生400uS间隔
TCNT1L = 0x00;
OCR1A = 400;
TCCR1B = 0x02;
TIMSK |= 0x10; //比较匹配中断
PPM_SET; //输出先置高
}
/****************************
* TC1初始化函数 *
* 功 能:产生各脉冲 *
* 预 分 频:8 *
* 工作模式:比较匹配中断 *
* 时钟频率:外部8.0000Mhz *
****************************/
void timer1_init(void)
{
TCCR1B = 0x00;
TCCR1A = 0x00;
// TCCR1B = 0x02;
}
/****************************
* TC1中断入口函数 *
****************************/
#pragma interrupt_handler timer1_ovf_isr:iv_TIMER1_COMPA
void timer1_ovf_isr(void)
{
TCNT1H = 0;
TCNT1L = 0;
flag ++;
switch(flag)
{
case 1:
OCR1A = ch_ad[0];
PPM_CLR; //置0
break;
case 3:
OCR1A = ch_ad[1];
PPM_CLR; //置0
break;
case 5:
OCR1A = ch_ad[2];
PPM_CLR; //置0
break;
case 7:
OCR1A = ch_ad[3];
PPM_CLR; //置0
break;
case 9:
OCR1A = ch_ad[4];
PPM_CLR; //置0
break;
case 11:
OCR1A = ch_ad[5];
PPM_CLR; //置0
break;
case 13:
PPM_CLR; //置0
flag = 0;
TIMSK &= ~0x10; //关闭TC1中断,等待下一帧到来
TCCR1B = 0x00;
break;
default:
OCR1A = 400;
PPM_SET; //置1
break;
}
}
/****************************
* 器件初始化函数 *
****************************/
void init_devices(void)
{
CLI();
port_init();
timer0_init();
timer1_init();
adc_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x01; //开启TC0溢出中断
// TIMSK = 0x45;
SEI();
}
/********************************
* 电压读取函数 *
* 入口参数:无 *
********************************/
void v_read(void)
{
uchar k;
for(k=0;k<6;k++)
{
ADMUX=0x40+k; //选择输入端电压通道
delay_us(500); //延时稳定
ch_sj[k] = ADC_Convert(); //读电压
delay_us(5);
ch_sj[k] = ADC_Convert(); //再读电压
}
ADMUX=0x46; //选择输入端电压通道
delay_us(500); //延时稳定
dy_sj = ADC_Convert();
delay_us(5);
dy_sj = ADC_Convert();
delay_us(50);
}
/********************************
* 混控功能函数 *
* 功能描述:实现两通道混控 *
* 入口参数:需混控的通道号 *
********************************/
void mix1(uchar a,uchar b)
{
ch_sj[a]=(ch_sj[a]+ch_sj[b])/2;
ch_sj[b]=511+ch_sj[a]/2-ch_sj[b]/2;
}
/****************************
* 主函数 *
****************************/
void main(void)
{
unsigned char m=0;
unsigned char n=0;
unsigned char a=0;
unsigned char z=0,f=0;
unsigned char flag=0; //定义数据标志
init_devices(); //器件初始化
ee_read();
LED_ON;
spk(1,800);
while(1)
{
v_read();
ch_fx = PINC; //读通道反向开关状态
f ++;
if(f>100)
{
f = 0;
z = ch_fx ^ z;
switch(z)
{
case 0x01:
ch_wt[0] = 580;
ee_write(ch_wt[0],0);
break;
case 0x02:
ch_wt[1] = 580;
ee_write(ch_wt[1],1);
break;
case 0x04:
ch_wt[2] = 580;
ee_write(ch_wt[2],2);
break;
case 0x08:
ch_wt[3] = 580;
ee_write(ch_wt[3],3);
break;
default:break;
}
z = PINC;
}
if((ch_fx & 0x40)==0) //飞翼混控开
{
mix1(0,1); //1、2通道混控
}
if((ch_fx & 0x80)==0) //V型混控开
{
mix1(1,3); //2、4通道混控
}
if((ch_fx & 0xC0)==0) //襟翼混控开
{
mix1(0,5); //1、6通道混控
}
if(ch_fx & 0x01) //1通道数据计算
{
ch_ad[0] = ch_sj[0]+ch_wt[0]; //正向
}
else
{
ch_ad[0] = fxsj-ch_sj[0]-ch_wt[0]; //反向
}
if(ch_fx & 0x02) //2通道数据计算
{
ch_ad[1] = ch_sj[1]+ch_wt[1]; //正向
}
else
{
ch_ad[1] = fxsj-ch_sj[1]-ch_wt[1]; //反向
}
if(ch_fx & 0x04) //3通道数据计算
{
ch_ad[2] = ch_sj[2]+ch_wt[2]; //正向
}
else
{
ch_ad[2] = fxsj-ch_sj[2]-ch_wt[2]; //反向
}
if(ch_fx & 0x08) //4通道数据计算
{
ch_ad[3] = ch_sj[3]+ch_wt[3]; //正向
}
else
{
ch_ad[3] = fxsj-ch_sj[3]-ch_wt[3]; //反向
}
if(ch_fx & 0x10) //5通道数据计算
{
ch_ad[4] = ch_sj[4]+zhd; //正向
}
else
{
ch_ad[4] = fxsj-ch_sj[4]-zhd; //反向
}
if(ch_fx & 0x20) //6通道数据计算
{
ch_ad[5] = ch_sj[5]+zhd; //正向
}
else
{
ch_ad[5] = fxsj-ch_sj[5]-zhd; //反向
}
m = ~PINB;
if(m)
{
delay_ms(20);
if(m==~PINB)
{
switch(m)
{
case 0x01:
if(ch_wt[0]<700)
{
ch_wt[0] += wtcs;
spk(1,sysc);
}
else
{
ch_wt[0]=700;
spk(1,sysc2);
}
if(ch_wt[0]==580)spk(1,sysc1);
ee_write(ch_wt[0],0);
break;
case 0x02:
if(ch_wt[0]>460)
{
ch_wt[0] -= wtcs;
spk(1,sysc);
}
else
{
ch_wt[0]=460;
spk(1,sysc2);
}
if(ch_wt[0]==580)spk(1,sysc1);
ee_write(ch_wt[0],0);
break;
case 0x04:
if(ch_wt[1]<700)
{
ch_wt[1] += wtcs;
spk(1,sysc);
}
else
{
ch_wt[1]=700;
spk(1,sysc2);
}
if(ch_wt[1]==580)spk(1,sysc1);
ee_write(ch_wt[1],1);
break;
case 0x08:
if(ch_wt[1]>460)
{
ch_wt[1] -= wtcs;
spk(1,sysc);
}
else
{
ch_wt[1]=460;
spk(1,sysc2);
}
if(ch_wt[1]==580)spk(1,sysc1);
ee_write(ch_wt[1],1);
break;
case 0x10:
if(ch_wt[2]<700)
{
ch_wt[2] += wtcs;
spk(1,sysc);
}
else
{
ch_wt[2]=700;
spk(1,sysc2);
}
if(ch_wt[2]==580)spk(1,sysc1);
ee_write(ch_wt[2],2);
break;
case 0x20:
if(ch_wt[2]>460)
{
ch_wt[2] -= wtcs;
spk(1,sysc);
}
else
{
ch_wt[2]=460;
spk(1,sysc2);
}
if(ch_wt[2]==580)spk(1,sysc1);
ee_write(ch_wt[2],2);
break;
case 0x40:
if(ch_wt[3]<700)
{
ch_wt[3] += wtcs;
spk(1,sysc);
}
else
{
ch_wt[3]=700;
spk(1,sysc2);
}
if(ch_wt[3]==580)spk(1,sysc1);
ee_write(ch_wt[3],3);
break;
case 0x80:
if(ch_wt[3]>460)
{
ch_wt[3] -= wtcs;
spk(1,sysc);
}
else
{
ch_wt[3]=460;
spk(1,sysc2);
}
if(ch_wt[3]==580)spk(1,sysc1);
ee_write(ch_wt[3],3);
break;
default:break;
}
delay_ms(200);
}
}
/* while(m=~PINB)
{
delay_ms(10);
}*/
if(dy_sj<dy1) //如果电压低于7.4V
{
if(dy_sj>dy2) //电压大于7V:慢闪报警
{
n ++;
if(n>=100)
{
n=0;
LED_TG;
spk(1,20);
}
}
else //电压小于7V:快闪报警
{
LED_TG;
spk(1,20);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -