⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 function.c

📁 51单片机C语言常用模块与综合系统设计实例精讲
💻 C
字号:
#include <./Atmel/at89x52.h>
#include <stdio.h>
#include <absacc.h>
#include <intrins.h>
#include <string.h>
#include "source.h"
#define FSUCCESS 0
#define FERROR   1  
#define FDOVER   2
bit TDBdata_over;
unsigned char dst_buf[DST_LEN];/*为数据传输口的发送缓冲区.*/
unsigned char dst_head;        /*为目前要发送数据存储的位置*/
unsigned char dst_tail;        /*为真正发送数据存储的位置,当head和tail相等时表明发送数据缓冲区无数据*/
unsigned char dsr_buf[DSR_LEN];/*接收数据缓冲区*/
unsigned char dsr_head;        /*从串口接收到的数据存储的位置*/
unsigned char dsr_tail;        /*从串口接收缓冲区读取数据的位置,当tail和head相等时间标兵接收缓冲区无数据*/
void delay_macnine_ncircle(unsigned char cnt){//11+6*cnt machin circle.
	while(cnt--);
}
void delay_10us(unsigned char tus){/*在C51时钟的频率为18.432MHZ时,延时10微秒*/
	tus--;
	while(tus--){
		_nop_();_nop_();_nop_();
		_nop_();_nop_();_nop_();
		_nop_();_nop_();_nop_();
	}
}
void print_sbuf(unsigned char c){/*向串口发送缓冲区中写数据*/
	dst_buf[dst_head]=c; 
	dst_head ++;
	dst_head %=DST_LEN; 
}
#define REPLAY_LEN 9
void reply_dwn(unsigned char flag,unsigned char *rbuf){/*rbuf 是下载的数据的指针,此函数是对下载的数据进行应答*/
	unsigned char reply[REPLAY_LEN];
	struct  yushi rply_crc;
	unsigned char i;
	reply[0]=FDWN_FHD;
	reply[1]=flag;
	reply[2]=rbuf[2];
	reply[3]=rbuf[3];
	reply[4]=rbuf[4];
	reply[5]=0x00;
	reply[6]=0x00;
	init_crccheck(&rply_crc);
	for(i=0;i<7;i++){
		crccheck(reply[i],&rply_crc);
	}
	reply[7]=rply_crc.h;
	reply[8]=rply_crc.l;
	for(i=0;i<REPLAY_LEN;i++){	
		print_sbuf(*(reply+i));
	}
	TI=1;
}
#define ERASE_SECTOR 
void flash_download(void){/*数据下载,等在数据下载完毕后此函数才退出*/
	union SFADD   dwn_adres;
	unsigned char fdata[FDWN_LEN];
	unsigned char fsm_fdl;
	unsigned char cnt;
	unsigned char erase_sec=0;
	unsigned int  sector_section=0;
	unsigned char temp;
	struct yushi fcrc;
	fsm_fdl=0;
	while(1){/*进入死循环,只有计算机把所有的数据下载完毕才推出*/
		if(dsr_tail!=dsr_head){/*串口接收缓冲区中有数据*/	
			if(fsm_fdl==0){/*串口接收在寻找帧头(0X7E)的状态*/
				if(dsr_buf[dsr_tail]==FDWN_FHD){/*串口接收的数据是帧头*/
					fsm_fdl=1;/*把串口接收的状态设置为接收数据*/
					fdata[0]=FDWN_FHD;/*把接收到的字节存储在接收的数据中*/
					cnt=1;
				}
			}
			else if(fsm_fdl==1){/*串口的状态在接受数据状态*/
				if(cnt<FDWN_LEN-1){/*135个字节的帧还没有接收完毕*/
						fdata[cnt]=dsr_buf[dsr_tail];
						cnt++;
				}
				else{/*一帧数据接收完毕*/
					fdata[cnt]=dsr_buf[dsr_tail];
					if(1){//mult_crccheck(fdata,FDWN_LEN,struct &fcrc)==0){/*由于串口出错的概率比较小,没有进行CRC效验*/
						dwn_adres.c[1]=fdata[2];/*提取出要写到flash的地址字节*/
						dwn_adres.c[2]=fdata[3];
						dwn_adres.c[3]=fdata[4];
#ifdef ERASE_SECTOR
						sector_section=dwn_adres.c[1];/*把地址字节转化为扇区地址*/
						sector_section <<=8;
						sector_section &=0xff00;
						sector_section |=dwn_adres.c[2];
						sector_section >>=5;
						if(((dwn_adres.c[2]&0x1f)==0x00)&&(dwn_adres.c[3]==0x00)){/*如果A0~A11为0,那么就表明要写的数据跨越扇区了,需要对扇区进行擦除*/
 					    if(sector_section<8){/*是扇区0~7(SA0~SA7)*/
								erase_sec=(unsigned char)sector_section;/*设置要擦除的扇区*/
								delay_10us(15);
								if(erase_sector(erase_sec)){/*返回1表明擦除成功*/
								}
								else{
									reply_dwn(erase_sec,fdata);
								}
							}
							else if((sector_section&0x7)==0){/*表明要跨越64K字节大小的扇区,扇区是SA8-SA70*/
								sector_section >>=3;
								erase_sec=(unsigned char)(sector_section&0xff);
								erase_sec +=7;/*计算出要擦除的扇区*/
								delay_10us(15);
								if(erase_sector(erase_sec)){/*返回1表明擦除成功*/
								}
								else{
									reply_dwn(erase_sec,fdata);
								}
							}
						}
#endif
						for(cnt=0;cnt<128;cnt++){/*把128字节的数据写到Flash中*/
							write_flash(&dwn_adres,fdata[5+cnt]);
							dwn_adres.l ++;/*没写一个字节,写falsh的地址增加1*/
						}
						if(fdata[1]==0x00){/*收到计算机的是数据下载类型,返回接收数据成功*/
							reply_dwn(FSUCCESS,fdata);
						}
						else if(fdata[1]==0x01){/*计算机通知所有数据下载完毕*/
							reply_dwn(FDOVER,fdata);/*对帧进行应答*/
							return;/*函数返回*/
						}
					}
					else{//CRC error
						reply_dwn(FERROR,fdata);
					}
					fsm_fdl=0;/*继续搜索下一帧的帧头*/					
				}
			}	
			dsr_tail++;
			dsr_tail %=DSR_LEN;
		}
		else{/*等待串口中断接收新的数据到数据接收缓冲区中*/
		}
	}
}

void init_serial(void)/*串行异步口初始化*/
{ 
    unsigned char ch;
   	SCON = 0x50;    // SCON /    MODE 1              /* setup serial port control /
    ch=TMOD;
	ch=ch&0x0f;
	TMOD=ch|0x20;       
	PCON=0XF0; // DIV 16
#ifdef FOSC18432
  	TH1=251;
  	TH0=TH1; /**hardware (19.2k baud @18.432)***/
	TR1=1; // let timer 1 run      // TCON /
#else
#ifdef FOSC24M
  	TH1=243;
  	TH0=TH1; /**hardware (9.6k baud @24M) infect is 9.61k*/
	TR1=1; // let timer 1 run      // TCON /
#else 
    //nothing 
#endif
#endif
	ES=1;//serial interrupt
}
#define ULWRCYCLE   FLASHADD=0X00;XBYTE[0X4AAA]=0XAA;XBYTE[0X4555]=0X55    /*Flash的非锁定写周期*/
#define WRITE_CMD 	ULWRCYCLE;FLASHADD=0X00;XBYTE[0X4AAA]=0XA0            /*Flash的写命令*/
#define ERASE_CMD   ULWRCYCLE;FLASHADD=0X00;XBYTE[0X4AAA]=0X80;ULWRCYCLE  /*Flash的擦除扇区命令*/
#define ERASE_CHIP  ERASE_CMD;FLASHADD=0X00;XBYTE[0X4AAA]=0X10            /*Flash的擦除整个芯片命令*/
bit erase_sector(unsigned char sa){/*扇区擦除命令,参数sa为要擦除的扇区为0~70*/
	unsigned int n;
	unsigned char cnt;
	unsigned char temp;
	unsigned char rybystat;
	ERASE_CMD;
	temp=sa;
	if(sa<8){/*是flash中的boot扇区,每个扇区的大小为8K字节*/
		cnt=temp;
		temp >>=1;
		FLASHADD=temp;
		if(cnt%2){/*扇区不同扇区的扇区地址是不同的*/
			XBYTE[0X2000+FLASH_MEM_SPACE_START]=0X30;/*擦除扇区命令*/
		}
		else{
			XBYTE[FLASH_MEM_SPACE_START]=0X30;/*擦除扇区命令*/
		}
	}
	else{/*是每个扇区为64K字节的扇区*/
		cnt=temp-7;
		temp=cnt <<2;
		FLASHADD=temp;
		XBYTE[FLASH_MEM_SPACE_START]=0X30;/*擦除扇区命令*/
	}	
	rybystat=FLASHRYNBY;
	for(n=0;n<2000;n++){/*如果RY/BY#管脚变低,表明擦除命令真正开始*/
		if(rybystat&0x01==0x00){//start erase.				
			goto my_exit;//break;
		}
		rybystat=FLASHRYNBY;
	}
my_exit:
	while(1){
		rybystat=FLASHRYNBY;
		if(rybystat&0x01==0x01){/*如果RY/BY#变低表明擦除完毕*/	
			break;
		}
	}
	if(n>=2000){/*擦除命令由于某种原因不能开始,退出程序*/
		return 0;
	}
	return 1;
}
void erase_flash(unsigned char flag,unsigned char sa){/*flag为0,擦除整个芯片,flag为1,擦除sa指定的扇区,可以由外部命令调用*/
	unsigned char cnt;
	unsigned char temp;
	unsigned char rybystat;
	if(flag==0){
		ERASE_CHIP;/*擦除整个芯片*/
	}
	else{
		ERASE_CMD;
		temp=sa;
		if(sa<8){//this is boot sector and is 8k pre sector.
			cnt=temp;
			temp >>=1;
			FLASHADD=temp;
			if(cnt%2){
				XBYTE[0X2000+FLASH_MEM_SPACE_START]=0X30;//erase sector of flash cmd.
			}
			else{
				XBYTE[FLASH_MEM_SPACE_START]=0X30;//erase sector of flash cmd.
			}
		}
		else{//it is 64k pre sector.
			cnt=temp-7;
			temp=cnt <<2;
			FLASHADD=temp;
			XBYTE[FLASH_MEM_SPACE_START]=0X30;//erase sector of flash cmd.
		}	
	}
	for(cnt=0;cnt<250;cnt++){
			rybystat=FLASHRYNBY;
			if((rybystat&0x01)==0x00){/*擦除开始*/
				goto exit_for;
			}
	}
exit_for:
	if(cnt>=250){/*擦除出错*/
	}
	else{
		while(1){
			rybystat=FLASHRYNBY;
			if((rybystat&0x01)==0x01){/*擦除完成*/	
				break;
			}
			else{
				cnt++;/*正在擦除中*/
			}
		}
	}
}
void write_flash(union SFADD  *p_add,unsigned char dat){/*向p_add指向的地址中写数据dat*/
    unsigned int flashspace;
	union SFADD   dwn_adres;
	dwn_adres.l=p_add->l;
	flashspace=dwn_adres.i[1];
	flashspace &=0x3fff;
	flashspace +=FLASH_MEM_SPACE_START;
	dwn_adres.l <<=2;	
    WRITE_CMD;
    FLASHADD=dwn_adres.c[1];
    XBYTE[flashspace]=dat;
}
void read_flash(unsigned char hadd,unsigned int ladd,unsigned char len,unsigned char *buf){/*从flash的hadd和ladd组成地址中读取len个数据到buf中*/
    unsigned char cnt;	
    unsigned int flashspace;
    flashspace=0x4000;
    flashspace +=ladd&0x3fff;
    FLASHADD=hadd;
    for(cnt=0;cnt<len;cnt++){
        buf[cnt]=XBYTE[flashspace+cnt];
    }
}
void draw_picture(unsigned char orgx,unsigned int orgy){/*把存储在flash中的图片使用显示出来*/
	unsigned char row;
	unsigned int basex;
	unsigned int ladd;
	union SFADD offset;
	basex=0x8000+SCREEN_WIDTH*orgy+orgx;/*在显存储中的位置*/
	offset.l=FLASH_ADD_PICTURE_START;   /*图片在flash中的位置*/
	ladd=offset.i[1];
	ladd &=0x3fff;
	ladd |=FLASH_MEM_SPACE_START;      /*把图片在flash中的位置转换为单片机能表示的寻址的地址*/
	offset.l <<=2;                     /*flash地址的A0~A13*/
	FLASHADD=offset.c[1];             /*flash地址的A14~A21地址*/
	for(row=0;row<PICTURE_HEIGHT;row++){/*约定存储的图片宽度为PICTURE_WIDTH*8 高度为PICTURE_HEIGHT*/
		memcpy((unsigned char *)basex,(unsigned char *)ladd,PICTURE_WIDTH);/*显示图片中的一行,相当于写1行图片数据到显存中*/
		ladd +=PICTURE_WIDTH;/*图片数据指向下一行*/
		basex +=SCREEN_WIDTH;/*显存指向下一行*/
	}
	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -