老师,您好!mega48弄得我一头雾水了,救命ing!
我用mega48v-TQFP和nRF401、ICL7135做了一个电压采集无线数据通讯的小模块,电源部分是利用2V的电池升压到5V然后分别转换两路电源4.5V给cpu部分,模拟部分,高频部分供电的。我以前用的是at90s2313做的,现在换成mega48,其他电路没有修改过,包括PCB设计部分也没有做大的改动,我把原来的2313 程序移植到了Mega48上,我使用的是外部的3.6864MHZ晶体,外部有个复位芯片来给系统复位的。测试的时候我的看门狗没有启用的。因为熔丝位我没有编程。
#define _VOLT_GET 1 //是否使用外部中断采集电压
#define _IO_CHANGE 0 //是否更改TXEN,CS的控制IO
我的每个模块都有地址,电压采集采用模块递推的方式启动,比如,#1启动#2-6处于等待自己时隙状态,然后#2又启动#3-7,这样递推下去,只要中间不连续断掉5个模块我的启动链是可以启动所有的模块发送数据到我的无线服务器的。每个模块固定的响应时间为100ms超过了则自动进入下一个模块了。
1.我把熔丝设置为CKDIV8=1SUT="11"CKSEL="1101"其他的我采用默认值。
2.
我先用了测试定时器的程序来测试时钟设置,5ms用T0定时,用示波器观测是正确的。
3.然后我测试了异步串口通讯,用有线的方式通过PC串口调试器来观测发现数据是正确,响应的数据也是正常的。
4.接着我把弄了个nRF401的测试程序,每1s发送一帧数据,然后我在旁边用我以前自己制作无线监听头配合我做的一个监听软件来观察数据,正确的,然后把我手工焊接的8个电路板全部烧录这个程序,都是正常的。
5.接着我做了一个外部中断0的测试程序,因为我的数据采集是通过INT0中断产生的。采集的数据通过有线的方式把数据传到调试器,我对比协议格式,看到我的采集数据是可以跟我加的电压一致的,我调整采集源电压,对应的AD数据在变化,计算出来跟实际值是一致的,这就说明我的外部中断0启用了,而且服务程序也是正确的。
6.最后我开始把所有的模块集成起来,把所有的功能都实现,测试时间是在11.4上午,我把完整的程序编译后烧写到mega48中,用无线监听头配合后台测试软件发命令跟模块通讯,可以采集到模块的电压放大系数,序列号,和电压AD量,但是电压AD量居然为0,其他都正常,地址修改也正常。就只有AD不正常,我怀疑是Int0没有被正常启动,但是我对比了我的INT0测试程序和我集成后的程序是一样的,然后我把这个hex烧写到另外一个扳子上,不过不是通过nrf401发数据,是通过有线的方式,
发现程序居然没有响应我的后台命令,由于我开机会发送数据出来,这时是可以看到开机发送的数据,但是后台发命令不可以响应了。同样的一个hex用无线的方式可以响应,用有线就不可以了。nrf401也是通过TXD,RXD跟串口连接的,都是串口,却不能响应了。
请教:
老师对于这个现象,您可以帮我分析下是我的程序的原因?还是我的硬件有问题导致不稳定呢?
7.而且之前我发现我的控制nRF401模式的TXEN,CS引脚会开机后过段时间无故的失控,好象是有点象复位的感觉,因为我开机发送数据1帧,先把nRF401设置到发送模式TXEN=1,(CS=0是固定的频道选择是初始化时就设置好的以后不变化的);但是我发现有时候开机就发现 TXEN和CS居然成25ms的周期脉冲波形,高15ms,低10ms。有时候开机是正常的,只要我从串口发数据下去就出现那个波形,出现这个波形的时候,从调试器可以看到不断有开机测试帧的前20个字节的数据上来,之后的10个字节就是错误的。 但是有时候我开机又是正常的,而且响应也是正常的。异常现象出现在断电后迅速插上电,而且一旦出现这个现象后,即使断电重新开始仍然是那个现象。重新烧录程序后也是那样。
对于这个现象看起来好象是在复位,我的初步判断是这样的。但是我用示波器观测我的reset引脚没有发现任何复位信号。因为它是开机还会正常发送数据,只是响应了数据后就会出现这个问题。但是我的com0中断服务程序是专门测试过正常的啊。
请教:
老师,您说我这个现象又是什么原因呢?可以帮我分析下吗?好象这个现象把我之前测试通过的模块程序给推翻了。
8.但是在11.4上午的测试中,是同一个电路板,同一个测试程序,发现有可以了,效果跟11.3不同了,没有出现TXEN和CS周期性脉冲的现象了。 现象跟 《第6条》的一样。但是到了下午,我怀疑是PD4,PD3的第二功能影响了我的TXEN,CS的控制,所以把这个两个控制信号换到PD6,PD7,就只改了#define 宏,名称都没有变化,烧写进去,居然连通讯都不正常了,我可以看到发送指示灯在收到一个命令后有数据响应出来,因为它在闪烁,有数据发送它会闪烁一次。但是无线舰艇后台收不到,我怀疑是我的监听有问题,用一个狂发数据带地址16号的模块来测试,后台可以正常正确的收到数据。
说明它没有出问题。
然后我用这个16号狂发来启动我的这个AD模块(地址18号),发现在后台也可以收到他们的响应数据,16号在前面,紧跟着的是18号。但是电压数据还是0.
因此我无法判断是哪里有问题了。因此我外部中断给禁止了,把AD缓冲自己填了个常数进去,然后想来测试下,发现这时居然程序根本就不响应了,连开机都不发送了,再重新烧程序,开机可以发送,但是不能响应了。把同样的hex烧写到有线通讯的那个板子上也不行了。我把串口测试的那个程序烧到有线通讯的那个板子上响应是正常。
请教:
老师,您说这些不稳定是什么原因造成的呢?可以帮我分析下吗?
我现在被它弄的一头雾水了,我已经没有清晰的思路去判断是软件还是硬件出问题了。
特意来请教老师您帮我分析下,可以吗?
我在附件里把我的程序附上,希望您可以在有空的时候帮我分析下,给我个回复,好吗?
谢谢!
Email:songyifang@china-gold.com
QQ:346678927
MSN:Housevian@hotmail.com #include <iom48.h>
#include <inavr.h>
#include "Defines.c"
void main(void)
{
uchar i,flag1,crc_data;
int count;
eeprom_struct eep_copy;
uint temp_addr;
system_ini();
system_state=0x40;
send_data_ok=1;
while(1)
{
//__watchdog_reset();
/*=============================================================================*/
if(receive_ok)
{
receive_ok=0;
crc_data=calcrc(rece_data.s_u.trasmit_data,9);
if(crc_data==0)
{
/*数据转移到数据缓冲*/
for(i=0;i<7;i++)
cal_data.s_u.trasmit_data=rece_data.s_u.trasmit_data;
temp_addr=cal_data.s_u.trasmit_data;
temp_addr<<=8;
temp_addr|=cal_data.s_u.trasmit_data;//获得本机地址2B
system_state=cal_data.s_u.ram.s_commd; //获得主机的控制命令1B
if(!(system_state&0x04)) //是读还是写操作 1:写,0:读
{
if(system_state&0x40) //是单播还是点播 1:单,0:点
{
system_unlock=0; //肯定是单播读操作
/*==============================*/
count=system_site-temp_addr;
//用地址差来确定当前模块需要等待的时间而且不能超过5
/*==============================*/
if ( (count<=5) && (count>0) )
{
switch(count)
{
case 1:
TCNT1=t1_70ms;
break;
case 2:
TCNT1=t1_170ms;
break;
case 3:
TCNT1=t1_270ms;
break;
case 4:
TCNT1=t1_370ms;
break;
case 5:
TCNT1=t1_470ms;
break;
default:break;
}
/*==============================*/
start_t1();//开始定时
}
else
end_t1();
}
else //点播---读操作
if( temp_addr==system_site )
//if((temp_addr==system_site) && system_unlock)
send_data_ok=1;
}
/*==============================*/
else //当前收到的数据帧是写操作 //本地参数修改
{ /*检查地址匹配和判断是什么操作模式*/
if((!(system_state&0x40)) && (temp_addr==system_site) )//写操作&&点播
{
switch(system_state&0x18)//取出bit 4 3判断数据的状态类型
{
case seri://序列号b 01
flag1=0;
/*为什么要去跟0x01020301比较???*/
for(i=0;i<4;i++)
if(cal_data.s_u.ram.s_data!=serial)
flag1=1;
if(!flag1)
{
system_unlock=1;//进入解锁模式
//TCNT1=t1_200ms;
TCNT1=t1_1000ms;
start_t1();
}
//既然是修改序列号为什么没有做修改操作呢?
break;
case zoom://放大系数b 10
//__watchdog_reset();
if(system_unlock)
{
for(i=0;i<4;i++)
{ /*将放大系数写入EEPROM缓冲*/
system_zoom=cal_data.s_u.ram.s_data;
eep_copy.e_u.eeprom.a=system_zoom;
}
eep_copy.e_u.eeprom.e_addr=system_site;
eep_copy.e_u.eeprom.e_crc=calcrc(eep_copy.e_u.eep_data,6);
write_eeprom(eep_copy);//真正的修改到EEPROM中
//__watchdog_reset();
}
system_unlock=0;//退出解锁模式
end_t1();
break;
case site://通道地址b 11
//__watchdog_reset();
if(system_unlock)
{
system_site=cal_data.s_u.ram.s_data;
system_site<<=8;
system_site|=cal_data.s_u.ram.s_data;
for(i=0;i<4;i++)
eep_copy.e_u.eeprom.a=system_zoom;
eep_copy.e_u.eeprom.e_addr=system_site;
eep_copy.e_u.eeprom.e_crc=calcrc(eep_copy.e_u.eep_data,6);
write_eeprom(eep_copy);
//__watchdog_reset();
}
system_unlock=0;
end_t1();
break;
default:break;
}
}
}
}
}//?if(receive_ok)
/*=============================================================================*/
if(send_data_ok)//允许发送模式标志设置后进入
{
//__watchdog_reset();
send_data.s_u.trasmit_data=(system_site>>8)&0xff;
send_data.s_u.trasmit_data=system_site;
send_data.s_u.ram.s_commd=system_state;
switch(system_state&0x18)
{
case volt:
now_send_volt=1;
for(i=0;i<4;i++)
send_data.s_u.ram.s_data=data1;
now_send_volt=0;
break;
case seri:
for(i=0;i<4;i++)
send_data.s_u.ram.s_data=serial;
break;
case zoom:
for(i=0;i<4;i++)
send_data.s_u.ram.s_data=system_zoom;
break;
default:break;
}
send_data.s_u.ram.s_crc=calcrc(send_data.s_u.trasmit_data,7);
send();
system_state=0;
send_data_ok=0;
}//?if(send_data_ok)
/*=============================================================================*/
}
}
//****************************************
//函数功能:外部中断函数,采7135数据
//入口函数:无
//出口参数:无
//备注:PC=B原来是:PB=B
//现在是PB=D(D5是最高位)
//原来是PB=DPD6=D5
//1 9 9 9 9
//D5 D4 D3 D2 D1
//data保存原始数据;data1读取原始数据
//#pragma vector = INT0_vect
#if _VOLT_GET >0
#pragma vector = INT0_vect
__interrupt void Int0Service (void)
{
uchar a_d_temp;
uchar j;
EIMSK&=0xfe; //关闭外部中断0
//===================================//
j=0;
a_d_temp=PINC&0x0f; //取出BCD数据
a_d_temp&=0x0f; //去掉最高四位
while(a_d_temp) //高低位翻转由于硬件设计原因
{
j<<=1; //保存高位
j|=a_d_temp&0x01; //存入低位
a_d_temp>>=1; //移动一位到末端
}
a_d_temp=j&0x0f; //到此时已经获得了真正的BCD数据
switch(PINB&0x3e) //0011 1110PB5:对应最高位
{
case 0x02: //D5
data=a_d_temp&0x01;
//bcdbuf=a_d_temp;
break;
case 0x04: //D4
data=a_d_temp;
//bcdbuf=a_d_temp;
break;
case 0x08: //D3
data<<=4;
data|=a_d_temp;
//bcdbuf=a_d_temp;
break;
case 0x10: //D2
data=a_d_temp;
//bcdbuf=a_d_temp;
break;
case 0x20: //D1
data<<=4;
data|=a_d_temp;
data=0; //设置数据符号位为+
/*如果当前没有发送电压则转存数据*/
if(!now_send_volt)
{
for(j=0;j<4;j++)
data1=data;
}
//bcdbuf=a_d_temp;
break;
default:
break;
}
/*这里是原来的at90s2313使用的代码
a_d_temp=PINB&0x0f;//获取当前的数据
if(PIND&0x40)//判断是否为第五位最高位
data=a_d_temp&0x01;//四位半中的半位要么为0要么为1
else
{
switch(PINB&0xf0)//读高四位选择读取第几个数字
{
case 0x80://D1
data<<=4;
data|=a_d_temp;
data=0;
if(!now_send_volt)
for(j=0;j<4;j++)
data1=data;
break;
case 0x40:
data=a_d_temp;
break;
case 0x20:
data<<=4;
data|=a_d_temp;
break;
case 0x10://D4
data=a_d_temp;
break;
default:break;
}
}
*/
//===================================//
EIMSK|=0x01; //恢复外部中断0
}
#endif
//****************************************
//函数功能:中断接收函数
//入口函数:无
//出口参数:无
//****************************************
//#pragma vector = UART_RX_vect //2313使用
#pragma vector =USART_RX_vect
__interrupt void UartService (void)
{
uchar temp1,u_temp;
/*==========================*/
__disable_interrupt();
temp1=UDR0;//mega48使用
/*==========================*/
if(!header_length)//头ff 55 00
{
if(temp1==0xff)
header_length=1;
}
else
{
if(temp1==0x55)
header_length++;
else
{
if(!temp1)//0x00
if(header_length==2)
{
head_ok=1;
header_length=0;
data_length=0;
data_time=0;
goto exit;
}
header_length=0;
}
}
/*==========================*/
if(head_ok)
{ //因为在8515发出来时进行了数据重复3次
if(data_time==3)//每三个字节数据中选择一个
{
data_time=0;
/*===================*/
if(temp==temp)
u_temp=temp;
else if(temp==temp)
u_temp=temp;
else
u_temp=temp;
/*===================*/
rece_data.s_u.trasmit_data=u_temp;
}
temp=temp1;
}
/*==========================*/
if(data_length==9)
{
head_ok=0;
receive_ok=1;
data_length=0;
/*if(rece_data.s_u.ram.s_commd&0x80)//判断是否为复位命令
{
WDTCSR=0x08; //watch dag is 16ms
while(1);//让模块复位
}
*/
}
/*==========================*/
exit:
__enable_interrupt();
}
//*************************************************
//功能:定时器1,进行与无线发谢模块在时钟上同步,
//入口参数:
//出口参数:
//备注:计时函数,有INT0中断产生,注:晶振用3.6864M
//*************************************************
//#pragma vector = TIMER1_OVF1_vect //2313使用
#pragma vector =TIMER1_OVF_vect
__interrupt void Timer1Service (void)
{
end_t1();
if(system_unlock)
system_unlock=0;
else
send_data_ok=1;
}
//*************************************************
//功能:定时器0, 用做5ms延时和25ms关trasmit_mode
//入口参数:
//出口参数:
//备注:计时函数,有INT0中断产生,注:晶振用3.6864M
//*************************************************
//#pragma vector = TIMER0_OVF0_vect //2313使用
#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0Service (void)
{
TIFR0|=0x01;
end_t0();
receive_mode();
TIMSK0&=0xfe; //关闭t0中断mega48
}
-----此内容被Houseivan于2005-11-05,10:42:30编辑过
//==================define.c=============================//
//****************************************
//函数功能:进行定时器,串口等初始化操作
//入口函数:无
//出口参数:无
//***************************************
#ifndef _DEFINE_C
#define _DEFINE_C
#define uchar unsigned char
#define uint unsigned int
#define _MCU_TYPE 1 //1:表示Mega48,0:表示90S2313
#define _DEBUG 0 //调试开关
#define _BAUD_9600 0 //1:Baud=9600;0:14400/19200
#define _VOLT_GET 1
#define _IO_CHANGE 0
#define _BAUD_RATE 14.4 //规定的串口波特率14.4K
#define _FOSC_VALUE 3686.4 //3.6864MHZ=3686.4KHZ
#define wirless_Address 0x12 //无线站址
#define t1_70ms 0xff03
#define t1_170ms 0xfd9b
#define t1_270ms 0xfc33
#define t1_370ms 0xfacb
#define t1_470ms 0xf963
#define t1_200ms 0xfd2f
#define t0_5ms 0xed
#define t0_25ms 0xa5
#define t0_40ms 0x6f
#define t1_1000ms 0xf1ef
#define volt 0x00
#define seri 0x08
#define zoom 0x10
#define site 0x18
/*===============函数宏表达式定义====================*/
#define display_on() PORTD&=0xdf
#define display_off() PORTD|=0x20
#define SET_TXD_H() PORTD|=0x02
#define SET_RXD_H() PORTD|=0x01
#define SET_TXD_IN() DDRD&=0xfd;
#define SET_TXD_OUT() DDRD|=0x02;
#define SET_RXD_IN() DDRD&=0xfe;
#define SET_RXD_OUT() DDRD|=0x01;
#if _IO_CHANGE>0
//TXEN:PD7/CS:PD6
#define SET_TXEN_H() PORTD|=0x80
#define SET_TXEN_L() PORTD&=0x7f
#define SET_CS_H() PORTD|=0x40
#define SET_CS_L() PORTD&=0xBF
#else
//TXEN:PD4/CS:PD3
#define SET_TXEN_H() PORTD|=0x10
#define SET_TXEN_L() PORTD&=0xef
#define SET_CS_H() PORTD|=0x08
#define SET_CS_L() PORTD&=0xF7
#endif
/*2313
#define Receive_Enable() UCR|=0x10 //串口允许接收
#define Receive_Disable() UCR&=0xef //串口禁止接收
#define trasmit_enable() UCR|=0x08 //串口允许发送
#define trasmit_disable() UCR&=0xf7 //串口允许发送
*/
//mega48使用
#define Receive_Enable() UCSR0B|=0x10 //允许接收
#define Receive_Disable() UCSR0B&=0xef //禁止接收
#define trasmit_enable() UCSR0B|=0x08 //允许发送
#define trasmit_disable() UCSR0BR&=0xf7 //允许发送
/*预定义宏:发送方式*/
#define trasmit_mode()\
{ \
SET_TXEN_H(); \
display_off(); \
}
/*预定义宏:接收方式*/
#define receive_mode()\
{ \
SET_TXEN_L(); \
display_on(); \
}
/*2313
#define start_t1() TCCR1B=0x05 //clk/1024,启动定时T1
#define end_t1() TCCR1B=0x00 //停止定时T1
#define start_t0() TCCR0=0x05 //clk/1024,启动定时T0
#define end_t0() TCCR0=0x00 //停止定时T0
*/
//mega48使用
#define start_t1() TCCR1B=0x05 //clk/1024,启动定时T1
#define end_t1() TCCR1B=0x00 //停止定时T1
#define start_t0() TCCR0B=0x05 //clk/1024,启动定时T0
#define end_t0() TCCR0B=0x00 //停止定时T0
/*输入输出定义*/
/*0b00000000*/
#define PB_direct_define DDRB=0x00
/*0b00000000*/
#define PB_data_define PORTB=0x00
/*0b11111010*/
#define PD_direct_define DDRD=0xfe
/*0b00000010*/
#define PD_data_define PORTD=0x02
/*0b00000000*/
#define PC_direct_define DDRC&=0x80
/*0b00000000*/
#define PC_data_define PORTC=0x00
void system_ini(void)
{
uchar m;
#if _DEBUG<1
uchar n,crc_data1,err;
eeprom_struct struct_back,good_eep;
#endif
float2char f_zoom;
/*============================*/
//TIMSK|=0x80; //开启T1 2313使用
TIMSK1|=0x01; //开启T1 mega48使用
//UCR|=0x80; //接收结束中断使能 2313使用
UCSR0B|=0x80; //接收结束中断使能 mega48使用 启用UART
#if _BAUD_9600>0 //这样做的好处是节约代码空间
//UBRR=23;
UBRR0=23
#else
//UBRR=15; //95--240023--9600 15--1440011--19200
UBRR0=11;
#endif
TCCR1A=0x00; //这里2313和mega48一致 T1采用定时方式
TCCR0A=0x00; //mega48专用
//MCUCR=0x02; //中断0下降沿触发? 2313使用
//GIMSK=0x40; //外中断0使能 2313
#if _VOLT_GET <1
data1=0x00;
data1=0x00;
data1=0x88;
data1=0x43;
#else
EICRA|=0x02; //中断0下降沿触发?mega48使用
EIMSK|=0x01; //外部中断0 请求使能
#endif
/*============================*/
PB_direct_define;
PB_data_define;
PC_direct_define;
PC_data_define;
PD_direct_define;
PD_data_define;
SET_CS_L();
receive_mode();
/*============================*/
end_t0();
end_t1();
/*============================*/
f_zoom.f_data=default_zoom;
#if _DEBUG<1
err=0;
for(m=0;m<=120;m+=40)
{
struct_back=copy_eeprom(m);
crc_data1=calcrc(struct_back.e_u.eep_data,8);
if(crc_data1)
err++;
else
{
good_eep=copy_eeprom(m);
system_site=good_eep.e_u.eeprom.e_addr;
for(n=0;n<4;n++)
system_zoom=good_eep.e_u.eeprom.a;
}
}
if(err)
{
if(err==4)
{
system_site=wirless_Address;
for(m=0; m<4; m++)
system_zoom=f_zoom.c_data;
}
else
write_eeprom(good_eep);
}
#else
system_site=wirless_Address;
for(m=0; m<4; m++)
system_zoom=f_zoom.c_data;
#endif
/*============================*/
//WDTCR=0x0b; //watch dog is 120ms2313
//WDTCSR=0x0b; //125ms mega48
/*============================*/
/*============================*/
header_length=0;
head_ok=0;
now_send_volt=0;
data_length=0;
system_unlock=0;
send_data_ok=0;
receive_ok=0;
/*============================*/
Receive_Enable();
trasmit_enable();
/*============================*/
__enable_interrupt();
/*============================*/
}
-----此内容被Houseivan于2005-11-05,10:45:58编辑过
页:
[1]