【实例86】总线接口的软件实现
/*引脚定义和相关头文件包含*/
#include
sbit I2C_SDA = P1^0;
sbit I2C_SCL = P1^1;
(1)函数void delay()
在C51中使用nop指令,实现一段时间的延时,程序代码如下:
void delay( void )
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
(2)函数void i2c_start()
void i2c_start( void )
{
I2C_SDA = 1;
I2C_SCL = 1;
delay();
I2C_SDA = 0;
delay();
I2C_SCL = 0;
}
(3)函数void i2c_stop()
void i2c_stop( void )
{
I2C_SDA = 0;
I2C_SCL = 1;
delay();
I2C_SDA = 1;
delay();
I2C_SCL = 0;
}
(4)函数void i2c_ ack ()
void i2c_ack( void )
{
I2C_SDA = 0;
I2C_SCL = 1;
delay();
I2C_SDA = 1;
I2C_SCL = 0;
}
(5)void i2c_send_byte()
/*输入参数: c */
void i2c_send_byte( unsigned char c )
{
unsigned char i;
for( i=8;i>0;i--)
{
if( c & 0x80 ) I2C_SDA = 1;
else
I2C_SDA = 0;
I2C_SCL = 1;
delay();
I2C_SCL = 0;
c = c<<1;
}
I2C_SDA = 1;
/*释放数据线,准备接收应答信号*/
I2C_SCL = 1;
delay();
while(!(0 == I2C_SDA
/*等待应答信号*/
&& 1 == I2C_SCL) ) ;
}
(6)函数unsigned char i2c_recv_byte()
/*输入参数: c */
/*返回数值:从 总线上读取的数据*/
unsigned char i2c_recv_byte( void )
{
unsigned char i;
unsigned char r;
I2C_SDA = 1;
for( i=8;i>0;i--)
{
r = r<<1;
/*左移补0*/
I2C_SCL = 1;
delay();
if( I2C_SDA ) r = r | 0x01 ;
/*当数据线为高时,数据位为1*/
I2C_SCL = 0;
}
return r;
}
【实例87】SPI总线接口的软件实现
程序中端口宏定义如下:
#include
#include
#define WREN 0x06
/*设置写使能锁存器*/
#define WRDI 0x04
/*复位写使用锁存器*/
#define RSDR 0x05
/*读状态寄存器*/
#define WRSR 0x01
/*写状态寄存器(看门狗和块锁)*/
#define READ 0x03
/*/读操作指令 0000 A8 011*/
#define WRITE 0x02
/*写操作指令 0000 A8 010*/
#define WIP 0x01
/*状态寄存器中写操作是否忙*/
/*各引脚定义*/
sbit X5045_SO = P1^1;
sbit X5045_SI = P1^6;
sbit X5045_SCK= P1^4;
sbit X5045_CS = P1^2;
(1)函数void write_byte()
/*入口:byte,要写入的8位数据*/
void write_byte( unsigned char byte )
{
unsigned char i;
unsigned char tmp;
for(i=0;i<8;i++)
{
X5045_SCK = 0;
tmp = byte & 0x80;
if( tmp == 0x80)
/*与0X80比较判断最高数据位是否为1*/
{
X5045_SI=1;
_nop_();
}
else
{
X5045_SI=0;
_nop_();
}
X5045_SCK = 1;
byte = byte<<1;
}
}
(2)函数unsigned char read_byte()
/*返回值:从X5045中读取的8位数据*/
unsigned char read_byte( void )
/*读数据,一次8位*/
{
unsigned char i;
unsigned char byte=0;
for(i=8;i>0;i--)
{
byte = byte<<1;
/*先读出的是高位*/
X5045_SCK = 1;
_nop_();
_nop_();
X5045_SCK = 0;
_nop_();
_nop_();
byte = byte|(unsigned char) X5045_SO;
}
return ( byte );
}
(3)函数void x5045_start()和void x5045_stop()
void x5045_start( void )
{
X5045_CS = 1;
_nop_();
_nop_();
X5045_SCK= 0;
_nop_();
_nop_();
X5045_CS = 0;
_nop_();
_nop_();
}
void x5045_end( void )
{
X5045_SCK = 0;
_nop_();
_nop_();
X5045_CS = 1;
_nop_();
_nop_();
}
(4)函数unsigned char x5045_read_status()
unsigned char x5045_read_status( void )
{
unsigned char tmp ;
x5045_start();
write_byte( RSDR );
tmp = read_byte( );
x5045_end();
return tmp;
}
(5)函数void x5045_write_status()
void x5045_write_status( unsigned char status )
{
unsigned char tmp ;
/*写操作之前先使能写操作*/
x5045_start();
write_byte( WREN );
x5045_end();
/*写入状态寄存器*/
x5045_start();
write_byte( WRSR );
write_byte( status );
x5045_end();
/*检查写操作是否完成*/
do
{
x5045_start();
write_byte( RSDR );
/*RSDR read status regesiter*/
tmp = read_byte();
x5045_end();
}
while( tmp & WIP ) ;
}
(6)函数unsigned char read_addr_data()
/*函数入口:addr,要读取数据的地址*/
unsigned char read_addr_data( unsigned int addr )
{
unsigned char addr_tmp,tmp;
unsigned char read_cmd ;
if( addr > 255 ) read_cmd = READ|0X08;
/*如果超出了一页,则名字字节A8为1*/
else
read_cmd =
READ;
addr_tmp = (unsigned char) (addr&0xff )
;
x5045_start();
write_byte( read_cmd );
write_byte( addr_tmp );
tmp = read_byte();
x5045_end();
return tmp;
}
(7)函数void write_addr_data()
/*入口地址:addr,要写入数据的地址*/
void write_addr_data( unsigned int addr,unsigned char edata )
{
unsigned char tmp,addr_tmp;
unsigned char cmd_tmp;
/*写使能操作*/
x5045_start();
write_byte( WREN );
x5045_end();
/*地址和写操作指令调节*/
if( addr >255 ) cmd_tmp = WRITE | 0x08;
else
cmd_tmp = WRITE;
addr_tmp = (unsigned char )( addr & 0xff );
/*向指定地址写入数据*/
x5045_start();
write_byte( cmd_tmp );
write_byte( addr_tmp );
write_byte( edata );
x5045_end();
/*检查写操作是否完成*/
do
{
x5045_start();
write_byte( RSDR );
tmp = read_byte();
x5045_end();
}
while( tmp & WIP ) ;
}
(8)函数void reset_wdt()
void reset_wdt( void )
{
X5045_CS = 0;
_nop_();
_nop_();
X5045_CS = 1;
nop_();
_nop_();
}
【实例88】1-WIRE总线接口的软件实现
(1)函数void _1wire_init()
/*包含头文件*/
#include
#include
/*引脚定义*/
sbit DQ = P1^2;
/*函数名称:单总线初始化*/
void init( void )
{
unsigned char i;
DQ = 1;
DQ = 0;
for( i = 200;i>0;i--) _nop_();
/*延时约600μs*/
DQ = 1;
for( i = 10;i>0;i--) _nop_();
/*延时约30μs */
while( DQ==1 );
for( i = 100;i>0;i--) _nop_();
/*延时约300μs*/
DQ = 1;
}
(2)函数void write_bit_1()
void write_bit_1(void)
{
unsigned char i;
DQ = 1;
DQ = 0;
for( i = 25;i>0;i--) _nop_();
/*延时约90μs */
DQ = 1;
}
(3)函数void write_bit_0()
void write_bit_0(void)
{
unsigned char i;
DQ = 1;
DQ = 0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DQ = 1;
for( i = 25;i>0;i--) _nop_();
/* 延时约90μs */
}
(4)另外仔细观察1-WIRE总线的写时序图,可将写“1”和写“0”合为一个函数。
void write_bit( bit D )
{
unsigned char i;
DQ = 1;
DQ = 0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DQ = D
for( i = 25;i>0;i--) _nop_();
/*延时约90us */
DQ = 1;
}
(5)函数bit read_bit()
bit read_bit( void )
{
unsigned char i;
DQ = 0;
for( i=0;i<5;i++)_nop_();
if( DQ == 1 )
{
return 1;
}
else
{
return 0;
}
}
(6)函数void write_byte()
void write_byte( unsigend char byte)
{
unsigned char i;
unsigned char tmp;
tmp = byte&0x01
for( i=0;i<8;i++)
{
tmp = byte>>i;
/*将要写的数据字节右移i位*/
tmp &= 0x01;
/*得到数据字节的第i位*/
write_bit( (bit)tmp );
}
}
(7)函数unsigned char read_byte()
unsigned char read_byte( void )
{
unsigned char i;
unsigned char tmp;
.
tmp = 0;
/*将返回值初始化为0*/
for(i=0;i<8;i++)
{
if( read_bit() )
/*如果当前读取的数据位为1*/
{
tmp = tmp | (0x01<
sbit rst=P3^5;
/*单片机与RTL8019AS复位线的接口*/
/*其他程序代码*/
rst=1;
/*RTL8019AS复位线高电平时复位*/
etherdev_delay_ms(100);
/*延时一段时间*/
rst=0;
选择寄存器组的一段程序:
#define reg00 xdata[0x0800]
/*其他程序代码*/
void page( unsigned char page_no )
{
unsigned char temp;
temp=reg00;
temp=temp&0x3B ;
/*0011 1011*/
page_no = page_no <<6;
temp=temp | page_no;
reg00=temp;
}
寄存器的设置情况:
#define reg00 xdata[0x8000]
#define reg01 xdata[0x8001]
/*其他程序代码*/
#define reg1f xdata[0x801f]
bit etherdev_init(void)
{
unsigned char tmp=0;
rst=1;
/*复位RTL8019*/
etherdev_delay_ms(100);
rst=0;
reg00=0x21;
/*0010 0001 CR
/*选择页0的寄存器,芯片停止运行,因为还/*没有初始化*/
page(0);
/*可以不加*/
reg01=0x4c;
/*Pstart,接收缓冲区首地址*/
reg02=0x50;
/*Pstop
50H*/
reg03=0x4c;
/*BNRY, 读页指针*/
reg04=0x40;
/*TPSR,发送缓冲区首地址*/
reg0a=0x00;
/*RBCR0 远程dma字节数低位*/
reg0b=0x00;
/*RBCR1 远程dma字节数高位*/
reg0c=0xcc;
/*RCR 接收配置寄存器 1100 1100*/
reg0d=0xe0;
/*TCR 传输配置寄存器 1110 0000*/
reg0e=0xc8;
/*DCR 数据配置寄存器 8位数据dma 1100 1000*/
reg0f=0x00;
/*IMR屏蔽所有中断*/
page(1);
/*选择页1的寄存器*/
reg07=0x4c;
/*CURR与??相等就会停止接收??*/
reg08=0x00;
/*MAR0
reg09=0x41; /*MAR1
reg0a=0x00; /*MAR2
reg0b=0x00; /*MAR3
reg0c=0x00; /*MAR4
reg0d=0x00; /*MAR5*/
reg0e=0x00;
/*MAR6*/
reg0f=0x00;
/*MAR7*/
/*写入MAC地址*/
reg01=ETHADDR0;
/*
reg02=ETHADDR1; /*
reg03=ETHADDR2;
/*
reg04=ETHADDR3;
/*
reg05=ETHADDR4;
/*
reg06=ETHADDR5;
/*
page(0);
reg00=0x22;
/*CR 0010 0010选择页0寄存器,芯片执行命令*/
reg07=0xff;
/*ISR*/
TR0 = 0;
/*以下为时钟脉冲初始化部分*/
TMOD &= 0xF0;
TMOD |= 0x01;
TH0 = ETH_T0_RELOAD >> 8;
TL0 = ETH_T0_RELOAD;
TR0 = 1;
ET0 = 1;
EA = 1;
return 1;
}
RTL8019发送数据包程序代码如下:
void etherdev_send(void)
/*发送数据包程序部分*/
{
unsigned int i;
unsigned char *ptr;
/*指针指向 的数据缓冲区*/
ptr = _buf;
page(0);
reg00=RD2 | STA;
/*终止DMA操作*/
while( reg00 & TXP) continue;
/*查询数据是否已经发送完?*/
reg07|=RDC;
/*清除ISR中远程DMA操作完成标志*/
reg08=0x00;
/*RSAR0*/
reg09=ETH_TX_PAGE_START;
/* RSAR1 设置远程DMA操作地址*/
reg0a=(unsigned char)( _len & 0xFF);
/* RBCR0远程dma字节数低位reg0b=(unsigned char)( _len >> 8 )*/
/* RBCR1远程dma字节数高位*/
reg00=RD1 | STA;
/*CR启动远程DMA写命令*/
for(i = 0; i < _len; i++)
{
/*单片机向RTL8019远程DMA写数据*/
if(i == 40 + _LLH_LEN)
{
ptr = (unsigned char *) _appdata;
}
reg10=*ptr++;
/* RDMA远程DMA端口,即8019接收数据的端口,*/
}
/*每写完一字节,自动加1*/
while(!(reg07 & RDC)) continue;
/*查询远程DMA是否完成?*/
reg00= RD2 | STA;
/*CR终止远程DMA操作*/
reg04=ETH_TX_PAGE_START;
/* TPSR设置发送缓冲区首地址*/
if( _len < ETH_MIN_PACKET_LEN)
{
/*以太网包的最小长度为60字节*/
_len = ETH_MIN_PACKET_LEN;
}
reg05=(unsigned char)( _len & 0xFF);
/*TBCR0发送数据包字节数*/
reg06=(unsigned char)( _len >> 8);
/*TBCR1 高低字节*/
reg00= 0x3E;
//RD2 | TXP | STA;
/*CR 启动发送命令*/
return;
}
(1)函数unsigned int etherdev_read()
unsigned int etherdev_read(void)
{
unsigned int bytes_read;
/* tick_count时钟滴答设置为0.5s,若读数据等待时间超过0.5s,则返回*/
while ((!(bytes_read = etherdev_poll())) && (tick_count < 12)) continue;
tick_count = 0;
return bytes_read;
}
(2)函数static unsigned int etherdev_poll()
static unsigned int etherdev_poll(void)
{
unsigned int len = 0;
unsigned char tmp;
/* 检查接收缓冲区是否有数据*/
if(reg07 & PRX)
{
/*PRX置位,表明数据包被正确接收*/
if( reg07 & OVW)
{
/*检查缓冲区是否溢出*/
bit retransmit = 0;
/*若缓冲区溢出,则丢弃缓冲区的所有数据包,我们无法保证溢出后*/
/*缓冲区的数据不受影响变化*/
reg00=RD2 | STP;
/* 终止当前DMA操作*/
reg0a=0x00;
/*复位远程数据计数器 低位*/
reg0b=0x00;
/*复位远程数据计数器 高位*/
/*当接收缓冲区发生溢出后,从缓冲区中读取一些数据而使其
/*不再处于溢出状态时,RST会被置位*/
while(!(reg07 & RST)) continue;
if(reg00 & TXP)
{
/*检测当前是否仍在传输数据*/
if(!((reg07 & PTX) || (reg07 & TXE)))
{
/*若无错误,则重发数据包*/
retransmit = 1;
}
}
reg0d=LB0;
/* TCR, LB0) */
reg00= RD2 | STA;
/*重新让RTL8019开始工作*/
reg03=ETH_RX_PAGE_START;
/*再重初始化BNRY*/
page(1);
reg07=ETH_RX_PAGE_START;
/*再重初始化CURR */
page(0);
reg07=PRX | OVW;
/*清除接收缓冲区溢出标志*/
reg0d=0x00;
/* TCR配置接收配置寄存器为正常工作状态*/
if(retransmit)
{
reg00=0x3e;
/*CR, RD2 | TXP | STA,重发数据包*/
}
}
else
{
/*接收缓冲区未溢出,读取数据包到 _buf缓冲区中*/
unsigned int i;
unsigned char next_rx_packet;
unsigned char current;
reg07=RDC;
/*ISR, RDC清除远程DMA完成标志位*/
reg08=0x00;
/* RSAR0设置远程DMA开始地址*/
reg09=reg03;
/*RSAR1=BNRY
reg0a=0x04;
/*RBCR0, 0x04设置远程DMA操作字节数,注意以太网帧头部4字节*/
reg0b=0x00;
/*RBCR1, 0x00
reg00=RD0 | STA;
/* CR, RD0 | STA
tmp=reg10;
/* RDMA,远程DMA读取第一个字节,为接收状态,不需要,注意*/
/*RTL8019接收数据包前4个字节并不是真正的以太网帧头,而是*/
/*接收状态(8BIT),下页指针(8BIT),以太网包长度(16Bit)*/
next_rx_packet =reg10;
/* RDMA,第二个字节为下一帧数据的指针*/
len = reg10;
/*RDMA,存储包的长度*/
len += (reg10<<8);
/* RDMA << 8*/;
len -= 4;
/*减去尾部CRC校验4字节*/
while(!(reg07 & RDC)) continue;
/*等待远程DMA操作完成*/
reg00=RD2 | STA;
/* CR 终止DMA操作*/
if(len <= _BUFSIZE)
{
/*检查数据包的长度*/
reg07=RDC;
/* ISR, RDC清除远程DMA操作完成标志*/
reg08=0x04;
/* RSAR0,设置远程DMA操作地址,前部分程序中并没有将*/
/*整个数据包//读入,只是读取接收数据包的前4个字节。*/
reg09=reg03;
*RSAR1=BNRY,BNRY中为 CURR
/*根据上文读取的数据包的长度设置远程DMA操作字节数寄存器*/
reg0a=(unsigned char)(len & 0xFF);
* RBCR0*/
reg0b=(unsigned char)(len >> 8);
* RBCR1*/
reg00=RD0 | STA;
/*etherdev_reg_write(CR, RD0 | STA) 读取数据包到 _buf中*/
for(i = 0; i < len; i++)
{
*( _buf + i) = reg10;
/* read RDMA*/
}
while(!(reg07 & RDC)) continue;
/*等待操作完成*/
reg00= RD2 | STA;
/*CR 远程DMA操作完成后终止*/
}
else
{
/*若数据包的长度太长, _buf将容纳不下丢弃此数据包len = 0 */
}
reg03=next_rx_packet;
/* BNRY=next_rx_packet,下页指针调整*/
page(1);
current = reg07;
/* 读取CURR指针*/
page(0);
if(next_rx_packet == current)
{
/* 检测上次接收的数据包是否已经被读走*/
reg07=PRX;
/*ISR, PRX 清除数据包被正确接收标志位*/
}
}
}
return len;
/*返回读取数据包的长度,数据已在 _buf中,若len=0,表明无数据*/
}
【实例92】单片机控制GPRS传输
函数send_gprs_data()实现发送指定长度数据的功能,本例中程序实现过程如下:
unsigned char send_gprs_data(
unsigned char *send_data_p,
/* 要发送数据的指针 */
unsigned int send_data_len
/* 发送数据的长度*/
)
{
/* ASCII 码形式存放的发送数据长度 */
unsigned char sd_len_asc[4];
/* 将要发送数据长度(16进制)转换为ASCII码形式 */
if( send_data_len <9 )
{
sd_len_asc[0]=send_data_len +0x30;
sd_len_asc_l =1;
}
else if( send_data_len <99 )
{
sd_len_asc[0] = (send_data_len%10) + 0x30 ;
sd_len_asc[1] = (send_data_len/10) + 0x30 ;
sd_len_asc_l = 2;
}
else if( send_data_len <999 )
{
sd_len_asc[0] = (send_data_len/100) + 0x30;
sd_len_asc[1] = (send_data_len%100)/10 + 0x30;
sd_len_asc[2] = (send_data_len%10 ) + 0x30;
sd_len_asc_l = 3;
}
else
{
sd_len_asc_l = 0;
}
/* AT命令发送要发送数据的长度 */
seri_send("AT+CIPSEND=",11);
seri_send(&sd_len_asc[0],sd_len_asc_l);
seri_send('\d',1);
/* 判断是否返回 " > " */
if( (seri_poll('>',1)==FALSE )||
(seri_poll('>',1)==TIME_OUT) )
{
return AT_CIPSEND_ERR;
}
seri_send( send_data_p,send_data_len);
/* 发送数据*/
seri_send('\d',1);
if((seri_poll("SEND OK",7)==FALSE )||
(seri_poll("SEND OK",7)==TIME_OUT) )
{
/* 检查发送是否成功 */
return SEND_ERR;
}
return GPRS_DATA_SEND_OK;
}
函数recv_gprs_data()主要完成对串行口接收数据简单处理的功能,seri_poll()函数的功能是在一段时间内查询串行口上是否有数据的功能。本例中程序如下:
unsigned char recv_gprs_data( void )
{
GPRS_DATA_HDR *gprs_data_p;
if( (seri_poll(NULL,0)==0)||
(seri_poll(NULL,0)==TIME_OUT))
/* 检查有无数据接收到 */
{
return NO_GPRS_DATA;
}
gprs_data_p = (GPRS_DATA_HDR *)&seri_recv_buf[0];
if( gprs_data_p->mask!=GPRS_DATA_SYN)
/* 检查数据接收的开始字符是否和法 */
{
clr_seri_buf();
return NO_MATCH_SYN;
}
gprs_recv_c ++;
if( (gprs_recv_c> 6 )&&
(gprs_recv_c<512)&&
( seri_recv_buf[ gprs_recv_c ] == FIN )
/* 检查结束字符 */
)
{
return GPRS_RECV_FRAME_OK;
/* 数据长度在GPRS_DATA_HDR结构中定义 */
}
else if( seri_recv_buf[gprs_recv_c>512]
{
clr_seri_buf();
return GPRS_FRAME_ERR;
}
else
{
return GPRS_RECVING;
}
}
程序中定义了数据的帧头格式,C语言中用结构体表示如下:
typedef struct
{
unsigned char syn_chr;
/* 起始字符*/
unsigned int data_len;
/* 本数据帧长度*/
unsigned int chk_sum;
/* 校验数据*/
unsigned char opt;
/* 功能域等*/
unsigned char *data_p;
/* 数据指针*/
}
GPRS_DATA_FRAME;
【实例93】单片机实现TCP/IP协议
上文中的例子将d加上volatile关键字后,如下:
#include
unsigned char a,b,c;
volatile unsigned char xdata d;
void main( void)
{
x=0xaa;
y=0xbb;
z=0xcc;
d=0xdd;
while(1)
{
x=d;
y=d;
z=d;
}
}
重新编译得到的代码(部分未列出)如下:
main:
MOV
x,#0AAH
MOV
y,#0BBH
MOV
z,#0CCH
MOV
DPTR,#d
MOV
A,#0DDH
MOVX
@DPTR,A
?C0001:
MOV
DPTR,#d
MOVX
A,@DPTR
MOV
x,A
MOVX
A,@DPTR
MOV
y,A
MOVX
A,@DPTR
MOV
z,A
SJMP
?C0001
END
uIP使用一结构体arp_hdr来表示ARP数据帧。
struct arp_hdr
{
struct uip_eth_hdr ethhdr;
/*以太网头部*/
u16_t hwtype,
/*硬件类型*/
protocol;
/*协议类型*/
u8_t hwlen,
/*硬件地址长度*/
protolen;
/*协议地址长度*/
u16_t opcode;
/*操作代码*/
struct uip_eth_addr shwaddr;
/*发送方硬件地址MAC地址*/
u16_t sipaddr[2];
/*发送方IP地址*/
struct uip_eth_addr dhwaddr;
/*接收方硬件地址MAC地址*/
u16_t dipaddr[2];
/*接收方IP地址*/
};
ethhdr:以太网头部。定义的结构体原型如下:
struct uip_eth_hdr
{
struct uip_eth_addr dest;
/*以太网目的地址 */
struct uip_eth_addr src;
/*以太网源地址 */
u16_t type;
/*数据帧类型*/
};
uIP并没有单独将IP帧拿出来进行单独处理,定义数据结构时直接将IP和TCP部分的头部放在一个结构体uip_tcpip_hdr中:
typedef struct
{
/* IP 帧头*/
u8_t
vhl,
/*4位版本和4位首部长度*/
tos,
/*8位服务类型*/
len[2],
/*16位总长度*/
ipid[2],
/*16位标识*/
ipoffset[2],
/*3位标志和13位偏移*/
ttl,
/*8位生存时间*/
proto;
/*8位协议*/
u16_t ipchksum;
/*16位首部校验和*/
u16_t srcipaddr[2],
/*源IP地址*/
destipaddr[2];
/*目的IP地址*/
/* TCP帧头*/
u16_t srcport,
/*16位源端口号*/
destport;
/*16位目的端口号*/
u8_t seqno[4],
/*32位序列号*/
ackno[4],
/*32位确认序列号*/
tcpoffset,
/*4位首部长度和保留位*/
flags,
/*标志*/
wnd[2];
/*窗口大小*/
u16_t tcpchksum;
/*16位校验和*/
u8_t urgp[2];
/*16位紧急指针*/
u8_t optdata[4];
/*选项数据*/
}
uip_tcpip_hdr;
每一个元素的类型为struct uip_conn型,uip_conn结构体定义如下:
struct uip_conn
{
u16_t ripaddr[2];
/*远程主机的IP地址*/
u16_t lport;
/*本地TCP端口*/
u16_t rport;
/*远程TCP端口*/
u8_t rcv_nxt[4];
/*期望收到的下一个顺序号*/
u8_t snd_nxt[4];
/*上次发送的顺序号*/
u16_t len;
/*预先发送的数据长度*/
u16_t mss;
/*本连接的最大报文大小*/
u16_t initialmss;
/*本连接的初始最大报文大小*/
u8_t sa;
/*重发数据超时计算状态变量*/
u8_t sv;
/*重发数据超时计算状态变量*/
u8_t rto;
/*重发数据超时*/
u8_t tcpstateflags;
/*TCP状态标志*/
u8_t timer;
/*重发数据定时器*/
u8_t nrtx;
/*上次重发数据段的序号*/
/*应用程序数据状态 */
u8_t appstate[UIP_APPSTATE_SIZE];
};
uIP0.9版本中应用程序部分带了一个简单的WEB服务器和只读文件系统,实现了简单的CGI功能。
void httpd_appcall(void)
{
u8_t idata i;
switch(uip_conn->lport)
{
case HTONS(80):
/* 判断是不是请求80端口 */
hs = (struct httpd_state xdata *)(uip_conn->appstate);
/* 得到当前的http状态 */
if(uip_connected())
{
hs->state = HTTP_NOGET;
hs->count = 0;
return;
}
else if(uip_poll())
{
if(hs->count++ >= 10)
{
uip_abort();
}
return;
}
else if(uip_newdata() && hs->state == HTTP_NOGET)
{
if( uip_appdata[0] != ISO_G ||
/* 如果不是get请求,丢弃数据 */
uip_appdata[1] != ISO_E ||
uip_appdata[2] != ISO_T ||
uip_appdata[3] != ISO_space)
{
uip_abort();
return;
}
for(i = 4; i < 10; ++i)
{
if(
uip_appdata[i] == ISO_space ||
uip_appdata[i] == ISO_cr ||
uip_appdata[i] == ISO_nl)
{
uip_appdata[i] = 0;
break;
}
}
if(uip_appdata[4] == ISO_slash && uip_appdata[5] == 0)
{
hs->script = NULL;
hs->state = HTTP_FILE;
hs->dataptr = web-12;
hs->count = sizeof(web)+12;
}
}
/*与else if(uip_newdata() && hs->state == HTTP_NOGET) */
if(hs->state != HTTP_FUNC)
{
if(uip_acked())
{
/* 如果上次发送的数据已经被接收,继续发送剩余的数据*/
if( hs->count >= uip_conn->len)
{
hs->count -= uip_conn->len;
hs->dataptr += uip_conn->len;
}
else
{
hs->count = 0;
}
if(hs->count == 0)
{
uip_close();
}
}
}
if(hs->state != HTTP_FUNC && !uip_poll())
/* 发送数据 */
{
uip_send(hs->dataptr, hs->count);
}
return;
default:
uip_abort();
break;
}
}
本文档为【51单片机应用开发范例大全(光盘)代码12】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。