📄 main.c
字号:
//##############################28J60初始化程序###########################//
void ENC28J60_Initialize(void)
{uchar state=0;
Reset_28J60();//软复位
delay(2);//28J60复位要一定的时间
while((state&0x01)==0)state=Read_Control_Register(ETH,0x1D);
//读状态寄存器ESTAT,确认CLKRDY时钟就绪位置1,确保已稳定,才能进行对MAC和PHY修改
Write_Control_Register(0x08,0x00);//ERXSTL
Write_Control_Register(0x09,0x08);//ERXSTH,ERXST指针指定接收数据包放在RAM中的开始位置
Write_Control_Register(0x0C,0x00);//ERXRDPTL
Write_Control_Register(0x0D,0x08);//ERXRDPTH,与ERXST值要保持相同
Write_Control_Register(0x00,0x00);//ERDPTL
Write_Control_Register(0x01,0x08);//ERDPTH,读数据包指针起始位置
Write_Control_Register(0x0A,0xff);//ERXNDL
Write_Control_Register(0x0B,0x1f);//ERXNDH,ERXND指针指定接收数据包放在RAM中的结束位置
//指定接收缓冲区,起始处接收缓冲区要预留至少7个字节,将接收到的数据包放入0x0800-0x1fff
Write_Control_Register(0x04,0x00);//ETXSTL
Write_Control_Register(0x05,0x00);//ETXSTH
enc28j60SetBank(0x01);//通过ECON1先选中当前控制寄存器组是Bank1,因为ERXFCON寄存器在Bank1。
Write_Control_Register(0x18,0x83);//将ERXFCON设定接收单播,广播的帧,丢掉CRC无效的数据包
enc28j60SetBank(0x02);//通过ECON1先选中当前控制寄存器组是Bank2,因为MAC相关寄存器在Bank2。
Bit_Field_Clear(0x01,0x80);//将MACON2中的MARST位清零,使MAC退出复位状态。
Write_Control_Register(0x00,0x0d);
//对MACON1进行配置,使能接收数据帧,如果是双工模式的话还要将TXPAUS和RXPAUS置1
Write_Control_Register(0x02,0x33);//对MACON3进行配置,配置MACON3中的PADCFG、TXCRCEN、FRMLNEN.
//大多数应用应使能自动填充(达到至少60字节),并始终追加一个有效的CRC.为了方便起见,许多应用可能还希望将FRMLNEN位置1
//使能帧长度状态报告.如果应用连接到全双工远程节点,则应将FULDPX置1,否则应保持该位清零。
Write_Control_Register(0x06,0x12);//配置非背对背包间间隔寄存器的低字节MAIPGL.大多数应用使用12h编程该寄存器。
//Write_Control_Register(0x07,0x0c);//如果使用半双工模式,应编程非背对背包间间隔寄存器的高字节MAIPGH.
//大多数应用使用0Ch编程该寄存器.
Write_Control_Register(0x04,0x15);//配置背对背包间间隔寄存器MABBIPG.
//当使用全双工模式时,大多数应用使用15h编程该寄存器,而使用半双工模式时则使用12h进行编程.
Write_Control_Register(0x0a,0xf0);//MAMXFLL
Write_Control_Register(0x0b,0x00);//MAMXFLH
//用允许接收或发送的最大帧长度编程MAMXFL寄存器.网络节点一般被设计为处理不大于1518字节的数据包.这里最大240
//如果使用半双工模式,还需编程重发和冲突窗口寄存器MACLCON1 和MACLCON2。
//大多数应用不需要更改默认的复位值。在网络线缆特别长的情况下,需要增加MACLCON2的默认值
enc28j60SetBank(0x03);//通过ECON1先选中当前控制寄存器组是Bank3,因为MAADR相关寄存器在Bank3.
Write_Control_Register(0x01,MACHead[6]);//MAADR0,将本地MAC地址写入MAADR0:MAADR5寄存器.
Write_Control_Register(0x00,MACHead[7]);//MAADR1
Write_Control_Register(0x03,MACHead[8]);//MAADR2
Write_Control_Register(0x02,MACHead[9]);//MAADR3
Write_Control_Register(0x05,MACHead[10]);//MAADR4
Write_Control_Register(0x04,MACHead[11]);//MAADR5
//接下去对PHY进行初始化//
Write_PHY_Register(0x00,0x01,0x00);//将PHCON1.PDPXMD置1,工作在全双工模式.
Write_PHY_Register(0x10,0x01,0x00);//将PHCON2.HDLDIS置1,禁止发送数据的自动环回。
Write_PHY_Register(0x14,0x04,0x72);//PHLCON寄存器配置LEDA,LEDB;LEDA显示链接状态,LEDB显示发送和接收活动
Bit_Field_Set(0x1e,0x80);//ECON2寄存器中的AUTOINC位置1,写缓冲器命令时自动指向下一个地址
Bit_Field_Set(0x1B,0xc0);//将EIE.INTIE位和EIE.PKTIE置1允许接收产生中断。
Write_Control_Register(0x1f,0x04);//接收使能
}
//##############################中断服务程序##################################//
void INT1_17(void)//接外部按键
{uchar i=0;
GICR &=0xbf;
//Transmit_Packets();//起动发送数据包
GICR |=0x40;
}
void INT0_16(void)
{uchar temp=0x00;//
GICR &=0x7f;
temp=Read_Control_Register(ETH,0x1f);//读取ECON1的值,先保护起来
do Receive_Packets();
while(EPKTCNT!=0);
Write_Control_Register(0x1f,0x00);//关接收使能
enc28j60SetBank(0x00);//通过ECON1先选中当前控制寄存器组是Bank0
Write_Control_Register(0x08,0x00);//ERXSTL
Write_Control_Register(0x09,0x08);//ERXSTH,ERXST指针指定接收数据包放在RAM中的开始位置
Write_Control_Register(0x0C,0x00);//ERXRDPTL
Write_Control_Register(0x0D,0x08);//ERXRDPTH,与ERXST值要保持相同
Write_Control_Register(0x00,0x00);//ERDPTL
Write_Control_Register(0x01,0x08);//ERDPTH,读数据包指针起始位置
Write_Control_Register(0x0A,0xff);//ERXNDL
Write_Control_Register(0x0B,0x1f);//
Write_Control_Register(0x1f,0x04);//接收使能
Write_Control_Register(0x1f,temp);//恢复ECON1的值
GICR |=0x80;
}
//####################################
void Usart_receive(void)//定义接收中断服务程序
{Rec232[usart_number]=UDR;
usart_number++;
TIMSK=0x01;//打开T1,T0中断屏蔽
TCCR0=0x05;//设T0分频数为1024
TCNT0=0xf0;//设T0时间常数,波特率数据流结束所对应的间隔
}
//##############定时器中断0,串行数据流控制
void Timer0(void)
{uchar i=0;
TIMSK=0x00;//关T0中断屏蔽
TCNT0=0x00;//
TCCR0=0x00;//T0停止计数
usart_number=usart_number-1;
DateLen=usart_number-42;//
if(Rec232[0]==0x04 && Rec232[1]==0x05 && Rec232[2]==0x06){
putchar(0x4F);putchar(0x4B);putchar(0x21);
}//连接成功回答OK!
if(Rec232[0]==0x4c && Rec232[1]==0x48 && Rec232[2]==0x46){//是不是LHF,是则发送
for(i=3;i<15;i++)MACHead[i-3]=Rec232[i];
for(i=15;i<35;i++)IpHead[i-15]=Rec232[i];
for(i=35;i<usart_number+1;i++)UDPpacket[i-23]=Rec232[i];
Transmit_Packets();}//发送数据
if(Rec232[0]==0x4d && Rec232[1]==0x41 && Rec232[2]==0x43){//是不是MAC 配置28J60
for(i=3;i<15;i++)MACHead[i-3]=Rec232[i];
for(i=15;i<35;i++)IpHead[i-15]=Rec232[i];
ENC28J60_Initialize();
delay(50);
putchar(0x4C);
putchar(0x48);
putchar(0x46);//发送"LHF"通知上位机,
for(i=0;i<12;i++)putchar(i);//配置成功则返回0,1,2,3,...11
}
usart_number=0;
}
//##############################USART初始化程序###########################//
void usart_init(void)
{
UCSRB=(1<<RXCIE)|(1<<RXEN)|(1<<TXEN);//允许发送和接收
UBRRL=(fosc/16/(bps+1))%256;
UBRRH=(fosc/16/(bps+1))/256;
UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据+1位STOP位
}
//##############################系统初始化程序################################//
void AVR_Initialize(void) //初始化
{
DDRA=0xff; //
PORTA=0xff;
DDRB=0xff; //
PORTB=0xff;
DDRC=0xc3; //
PORTC=0x00; //
DDRD=0xf0; //
PORTD=0x7f;
SPCR=0b01010000;
//关中断(SPIE=0),使能SPI(SPE=1),MSB首先发送(DORD=0),选择微机为主机模式(MSTR=1)
//空闲时SCK为低电平(CPOL=0),在SCK的上升沿采样(CPHA=0)ENC28J60要求SPI工作在模式0
//SPR1=0和SPR0=0,SCK=fosc/4
SPSR |=0x01;//SPI的速度加倍
MCUCR=0x0a;//设置外部中断的中断触发方式为下降沿触发
GICR=0xc0; //通用中断控制寄存器设置,打开中断INT0和INT1
SREG=0x80; //开全局中断
}
//##################################主程序####################################//
void main()
{delay(5);
AVR_Initialize(); //I/O口及中断初始化
usart_init();
//ENC28J60_Initialize();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -