/************************************** 硬件:单片机mega162,EEPROM 25256,晶振3.6864MHZ 编译环境:ICC ****************************************/ #include<iom162v.h> #define BAUD 9600 //波特率4800 #define CRYSTAL 3686400 //晶振3M #define BAUD_set (unsigned int)( (unsigned long)CRYSTAL/(16*(unsigned long)BAUD)-1 ) //波特率计算 #define BAUD_H (unsigned char)(BAUD_set>>8) //波特率寄存器 #define BAUD_L (unsigned char)(BAUD_set) /* //GPRS #define GPRS_ONOFFH PORTA|=(1<<PA5) #define GPRS_ONOFFL PORTA&=~(1<<PA5) #define GPRS_RSTH PORTB|=(1<<PB1) #define GPRS_RSTL PORTB&=~(1<<PB1) //通讯灯 #define LED1H PORTC|=(1<<PC4) #define LED1L PORTC&=~(1<<PC4) #define LED2H PORTC|=(1<<PC6) #define LED2L PORTC&=~(1<<PC6) #define LED3H PORTC|=(1<<PC7) #define LED3L PORTC&=~(1<<PC7) */ //25256 #define EEPROM_CSH PORTD|=(1<<PD5) // #define EEPROM_CSL PORTD&=~(1<<PD5) #define EEPROM_WPH PORTD|=(1<<PD2) #define EEPROM_WPL PORTD&=~(1<<PD2) #define SPIF 7 //////////////////////USRT0,USTR1 begin////////////////////////// /////////////////////////////////////串口begin/////////////////////////////////////////// //串口0初始化 void USART0_Init() { UCSR0B = (1 << RXCIE0) | /*接收完成中断允许*/ // (1 << TXCIE0) | /*发送完成中断允许*/ (1 << RXEN0) | /*接收允许*/ (1 << TXEN0); /*发送允许*/ UBRR0H = BAUD_H; //设置波特率 UBRR0L = BAUD_L; UCSR0C = (1 << URSEL0) | /*选择访问UCSRC寄存器*/ (3 << UCSZ00); /*UCSZ2 UCSZ1 UCSZ0=3 8个数据位*/ } //串口1初始化 void USART1_Init() { UCSR1B = (1 << RXCIE1) | /*接收完成中断允许*/ // (1 << TXCIE1) | /*发送完成中断允许*/ (1 << RXEN0) | /*接收允许*/ (1 << TXEN0); /*发送允许*/ UBRR1H = BAUD_H; //设置波特率 UBRR1L = BAUD_L; UCSR1C = (1 << URSEL1) | /*选择访问UCSRC寄存器*/ (3 << UCSZ10); /*UCSZ2 UCSZ1 UCSZ0=3 8个数据位*/ } //串口0查询方式发送数据 void USART0_Transmit(unsigned char data) { while(!(UCSR0A&(1<<UDRE0))); /*等待发送缓冲器为空。UDRE数据寄存器空标志位, 当发送缓冲器空时被置1;发送缓冲器包含需要发送的数据时清零*/ UDR0=data; //将数据放入缓冲器,发送数据 } //串口1查询方式发送数据 void USART1_Transmit(unsigned char data) { while(!(UCSR1A&(1<<UDRE1))); /*等待发送缓冲器为空。UDRE数据寄存器空标志位, 当发送缓冲器空时被置1;发送缓冲器包含需要发送的数据时清零*/ UDR1=data; //将数据放入缓冲器,发送数据 } /* //发送GPRS命令给手机模块 void USART1_Tx_Str(char *s,unsigned char cnt) { while(cnt--) { USART1_Transmit(*s); s++; } } */ /////////////////////////////////////////////串口end///////////////////////////////////// /* unsigned char usart0_receive(void) { while(!(UCSR0A&(1<<RXC0))); //等待接收数据 return UDR0; //从缓冲器中获取并返回数据 } */ ////////////////////////USRT1,USRT2 end/////////////////////// ///////////////////////////////////////////GPRS begin//////////////////////////////////// //延时ms /* void delayms(unsigned int ms) { unsigned int i,j; for(i=0;i<ms;i++) for(j=0;j<3500;j++) ; } //GPRS开机 void GPRS_On() { GPRS_RSTH; GPRS_ONOFFH; delayms(20); GPRS_RSTL; delayms(10); GPRS_ONOFFL;LED1L;LED2L;LED3L;delayms(1800); GPRS_ONOFFH;LED1H;LED2H;LED3H;delayms(200); LED1L;LED2L; } //GPRS关机 void GPRS_Off() { GPRS_ONOFFL;delayms(1800); GPRS_ONOFFH;delayms(5000); GPRS_RSTL; } //GPRS复位 void GPRS_Rst() { GPRS_Off(); GPRS_On(); } */ ////////////////////////////////////////GPRS end///////////////////////////////////////// ////////////////////////////////////eeprom begin////////////////////////////////////// void SPI_MasterInit(void) { EEPROM_WPH; delayms(20); SPCR =(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0); /* 使能SPI,选择主机模式,SCK=fosc/128,选择SPI模式CPOL=0,CPHA=0 */ } unsigned char SPI_MasterTransmit(unsigned char cData) { //启动数据传输 SPDR = cData; //等待数据传输结束 while(!(SPSR&(1<<SPIF))); //发送完成后,清除发送标志 // SPSR&=~(1<<SPIF); return SPDR; //每次发送数据的同时,也会接收到数据。 } //EEPROM写使能 void EEPROM_WREN() { EEPROM_CSL; //拉低片选端 SPI_MasterTransmit(0x06); //0x06为写使能的指令 EEPROM_CSH; //抬高片选端,结束 } //EEPROM写禁止 void EEPROM_WRDI() { EEPROM_CSL;//delayms(20); SPI_MasterTransmit(0x04); //0x04为写禁止的指令 EEPROM_CSH;//delayms(20); } //写状态寄存器 void EEPROM_WRSR() { EEPROM_WREN(); EEPROM_CSL; //使能 SPI_MasterTransmit(0x01); //0x01为写状态寄存器的指令 SPI_MasterTransmit(0x82); //把0x82写入状态寄存器 EEPROM_CSH; //抬高片选,结束 } /* 读状态寄存器。读SPI从机数据时,主机要给从机发送任意数据,才能收到从机返回的数据. 即0x00可以是任何数据(但是不能是25256的指令,例如0x01,0x04之类的) */ unsigned char EEPROM_RDSR() { unsigned char StatusReg; EEPROM_WREN(); // EEPROM_WRDI(); //如使用此句,不使用EEPROM_WREN(),则读出0x80 EEPROM_CSL; //使能 SPI_MasterTransmit(0x05); //0x05为读状态寄存器指令 StatusReg=SPI_MasterTransmit(0x00); //给25256发送任意数据 /* 此处原为: SPDR = 0x00; while(!(SPSR&(1<<SPIF))); StatusReg=SPDR; 时出错,读出数据都为0xff。想不清楚为什么 */ EEPROM_CSH; return StatusReg; } //25256字节写 void EEPROM_ByteWrite(unsigned int Address,unsigned char Data) { EEPROM_WREN(); EEPROM_CSL; //使能 SPI_MasterTransmit(0x02); //0x02为写指令 SPI_MasterTransmit(Address/256); //地址高位 SPI_MasterTransmit(Address%256); //地址低位 SPI_MasterTransmit(Data); //写入数据 EEPROM_CSH;delayms(50); } //25256页写。试验结果,只能连续写入三个字节 void EEPROM_PageWrite(unsigned int Address,unsigned char *Data,unsigned char NData) { unsigned char i; EEPROM_WREN(); EEPROM_CSL; SPI_MasterTransmit(0x02);//页写指令 SPI_MasterTransmit(Address/256); //地址高位 SPI_MasterTransmit(Address%256); //地址低位 for(i=0;i<NData;i++) { SPI_MasterTransmit(*Data); //写入数据 Data++; } EEPROM_CSH; } //25256读 unsigned char EEPROM_Read(unsigned int Address) { unsigned char dataa; EEPROM_CSL; //使能 SPI_MasterTransmit(0x03); //0x03为读25256的指令 SPI_MasterTransmit(Address/256); //地址高位 SPI_MasterTransmit(Address%256); //地址低位 dataa=SPI_MasterTransmit(0x00);//发送任意数据 EEPROM_CSH; return dataa; //返回读到的数据 } ////////////////////////////////////eeprom end//////////////////////////////////////// //端口初始化 void Port_Init() { PORTA=0xff; DDRA=0x30; //PA4,PA5输出1 PORTB=0xbf; DDRB=0xb7; //PB1输出1,PB2输出1,PB3输入0,PB4输出1,PB0输出1(用于新终端开关电源控制),PB5PB7为输出1 PORTC=0xff; DDRC=0xd0; //PC4输出1,PC6,PC7输出1 PORTD=0xff; DDRD=0x26; //PD0输入0,PD1输出1,PD5PD2输出1 } void main(void) { // unsigned char dataa,i,j; SREG=0x80; //开放全局中断 Port_Init(); USART0_Init(); USART1_Init(); // GPRS_On(); SPI_MasterInit();EEPROM_WRSR(); while(1) { USART0_Transmit(0x22); USART0_Transmit(0x33); EEPROM_ByteWrite(0x2030,0x48); //给25256地址0x2030写入数据0x48 USART0_Transmit(EEPROM_Read(0x2010)); USART0_Transmit(EEPROM_Read(0x2030));//读出地址0x2030中数据,从串口0发送出来 USART0_Transmit(0x44); USART0_Transmit(0x55); USART0_Transmit(EEPROM_RDSR()); EEPROM_PageWrite(0x1001,"456789",6); //输出结果0xff,0xff,0xff,0x37,0x38,0x39 USART0_Transmit(EEPROM_Read(0x1001)); USART0_Transmit(EEPROM_Read(0x1002)); USART0_Transmit(EEPROM_Read(0x1003)); USART0_Transmit(EEPROM_Read(0x1004)); USART0_Transmit(EEPROM_Read(0x1005)); USART0_Transmit(EEPROM_Read(0x1006)); USART0_Transmit(0x11); } } /* //IAR中中断的写法 #pragma vector=USART0_RXD_vect __interrupt void Usart0Rx(void) { unsigned char dataa; dataa=UDR0; usart0_transmit(dataa); } */ //串行0通信接收完成中断\ //ICC中中断的写法 #pragma interrupt_handler USART0Rx:20 void USART0Rx() { unsigned char data0; data0=UDR0; USART0_Transmit(data0); } /*串行1通信接收完成中断 分析灯不亮原因,开了串口1中断,但是没有加入中断函数,导致其他地方不能工作。 串口中断0能执行,是由于其优先级比串口中断1高 以下是书上的说法: 接收结束标志位(RXC)用来说明接收缓冲器中是否有未读出的数据。当接收缓冲器中有未读出的 数据时,此位为1,当接收缓冲器空时为0(即不包含未读出的数据)。如果接收器被禁止(RXEN=0), 接收缓冲器会被刷新,从而使RXC清零。 置位UCSRB的接收结束中断使能位(RXCIE)后,只要RXC标志置位(且全局中断使能)就会产生USART 接收结束中断。使用中断方式进行数据接收时,数据接收结束中断服务程序必须从UDR读取数据 以清除RXC标志,否则只要中断处理程序结束,一个新的中断就会产生。 终上所述,RXC标志未清零,导致中断一直产生。 */ #pragma interrupt_handler USART1Rx:21 void USART1Rx() { unsigned char data1; data1=UDR1; // USART1_Transmit(data1); }