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

📄 main.c

📁 AVRMega16单片机的项目
💻 C
📖 第 1 页 / 共 2 页
字号:
/**********************************************************************************************************
  								 陕 西 ?? 电 子 有 限 公 司
  Copyright (C), 2000-2008, LiFang Tech. Co., Ltd.
  File name:      // main.c
  Author:zhuxz		Version:v3.1	Date: 2008-8-29
  Description:    // 用于详细说明此程序文件完成的主要功能,与其他模块
                  // 或函数的接口,输出值、取值范围、含义及参数间的控
                  // 制、顺序、独立或依赖等关系
  Others:         // 其它内容的说明
	集成开发环境:ICCAVR6.31A	
  	主控芯片型号: ATMega16		
  	晶振频率:	  外部 7.3728MHZ	
  	波特率: 	  9600
**********************************************************************************************************/

#include <macros.h>
#include <string.h>
#include <stdlib.h>
#include <iom16v.h>
#include "main.h"
#include "initial.h"


#define TW_MR_SLA_ACK   0x40
#define TW_MR_SLA_NACK  0x48
#define TW_MR_DATA_ACK  0x50
#define TW_MR_DATA_NACK 0x58
#define TW_MTR_ARB_LOST 0x38
#define TW_MT_DATA_NACK 0x30
#define TW_MT_DATA_ACK  0x28
#define TW_MT_SLA_NACK  0x20
#define TW_MT_SLA_ACK   0x18
#define TW_REP_START    0x10
#define TW_START        0x08

#define  RECVBUFFERLEN  14
//UART接收到PC缓冲区的长度
uchar UartRecvBuffer[RECVBUFFERLEN];
//UART接收缓冲区的索引
uchar UartRecvIndex = 0;
//接收PC传来的UART完整一桢数据包标志
uchar  gbRecvPCFrameCmd  = 0;

//定义I2C总线的数据
//MCU I2C接收数据的缓存参数定义
uchar  I2cReceiveDataIndex = 0;
uchar  I2cReceiveDataLength= 0;
uchar  I2cReceiveData[16];
//MCU I2C发送数据的缓存参数定义
uchar  I2cSendData[16];
uchar  I2cSendDataIndex    = 0;
uchar  I2cSendDataLength   = 0;

//表明与I2C器件的通信状态(成功:TRUE/失败:FALSE)
uchar  gbi2cSendCmdStatus  = TRUE;
//MCU接收到I2C器件字节标志
uchar  gbi2cRecvByteStatus = FALSE;
//MCU发送出字节标志
uchar  gbi2cSendByteStatus = FALSE;

//Timer0溢出次数,用来控制刷卡时间
uint   gTmr0OvrCount     = 0;
//Timer2溢出次数,用来控制流水时间
uint   gTmr2OvrCount     = 0;

//键盘中断标志
uchar  cKeyRiseEvent     = 0;


//FLASH地址操作的变量
uint  gnCurrentFlashPage = 0;	//当前操作的页地址
uint  gnCurrentBytesBlock = 0;   //当前页内的字节块

uint  gnHistoryFlashPage = 0;	//历史操作的页地址
uint  gnHistoryBytesBlock = 0;   //历史页内的字节块




void  SoftDelay(void)
{
     uint loop = 0;
	 
     for (loop = 0; loop <1000; loop++);     
}

/*******************************************************************************
**             串口发送字节子程序 
*******************************************************************************/ 
void Uart_Send(uchar senddata) 
{ 
    UDR = senddata;
	
    while(!(UCSRA & (1<<UDRE)));  //等待发送完
	
    UCSRA |= 0x40;                //清“发送完”标志位 
}


/******************************************************************************* 
**             SPI发送字节子程序 
*******************************************************************************/
void SPI_MasterTransmit(uchar cData)
{ 
	 /* 启动数据传输 */
	 SPDR = cData;
	 /* 等待传输结束 */
	 while(!(SPSR & (1<<SPIF)));
}

//读取某页内字节地址的命令
uchar  SPI_ReadPageCtx(uint page/*0~4095*/, uint byteAddr/*0~263*/)
{
     uchar cData=0;
	 
	 CLRBIT(PORTB,4);
	 
     SPI_MasterTransmit(0x52); //CMD, 1st
     
	 cData = 0x1F & ((char)(page>>7));
	 SPI_MasterTransmit(cData);//Page Addr High,2nd
	 
	 cData = ((char)(page & 0x7F))<<1;
	 cData |= (char)((byteAddr & 0x1FF)>>8);
	 SPI_MasterTransmit(cData);//Page Addr low,3rd
	 
	 cData = (char)(byteAddr & 0xFF);
	 SPI_MasterTransmit(cData);//byte Addr High,4th
	 
	 //空命令,凑足剩余4字节
	 SPI_MasterTransmit(0);
	 SPI_MasterTransmit(0);
	 SPI_MasterTransmit(0);
	 SPI_MasterTransmit(0);
	 
	 /* 等待传输结束 */
	 while(!(SPSR & (1<<SPIF)));
	 cData = SPDR;
	 
	 SETBIT(PORTB,4);
	 return cData;
}

//写入某页内某字节地址的命令
void  SPI_WritePageCtx(uint page/*0~4095*/, uint byteAddr/*0~263*/, uchar cByte)
{
     uchar cData =0;
	 
	 CLRBIT(PORTB,4);
	 
	 //把数据写入Buffer1
     SPI_MasterTransmit(0x84); //CMD, 1st
	 SPI_MasterTransmit(0);    //Not Care
	 
	 cData |= (char)((byteAddr & 0x100)>>8);
	 SPI_MasterTransmit(cData);//Byte Addr High,3rd
	 
	 cData = (char)(byteAddr & 0xFF);
	 SPI_MasterTransmit(cData);//Byte Addr High,4th
	 
	 //传输字节
	 SPI_MasterTransmit(cByte);//Byte Data
	 
	 SETBIT(PORTB,4);
}

//擦除FLASH芯片所有内容
char  EraseFlashCtx(void)
{
     uchar bResult = 1;
     uchar cData   = 0;
	 char  page     = 0;
	 
	 CLRBIT(PORTB,4);
	 
	 for (page =0; page<4096; page++)
	 {
	  	 SPI_MasterTransmit(0x58); //CMD, 1st
	 	 cData = 0x1F & ((char)(page>>7));
	 	 SPI_MasterTransmit(cData);//Page Addr High,2nd
	 	 
	 	 cData = ((char)(page>>7))<<1;
	 	 SPI_MasterTransmit(cData);//Page Addr low,3rd
     	 
	 	 SPI_MasterTransmit(0);    //not care	 
	 	 
	 	 //读取状态寄存器
	 	 SPI_MasterTransmit(0x57);
		 
		 /* 等待传输结束 */
	     while(!(SPSR & (1<<SPIF)));
	 	 cData = SPDR;
		 
	 	 cData  &= 0x40;
	 	 bResult &= (cData == 0);
	 }
	 
	 SETBIT(PORTB,4);
	 return  bResult;
}

//向FLASH中写入已使用的总页数和字节数,或下一个页数和字节地址
void  WriteContextInfo(uint curpage/*当前页地址*/, 
	  					uchar curBlockIndex/*当前页内字节块的索引号*/)
{
 	 //页地址高字节和低字节(范围:22..4095),20个字节的倍数(范围:0..12)
     SPI_WritePageCtx(0, 0, (uchar)(curpage>>8));
	 SPI_WritePageCtx(0, 1, (uchar)(curpage&0xFF));
	 SPI_WritePageCtx(0, 2, curBlockIndex);
}

//确认当前消费记录写操作成功,完成写入和读出的记录钱数要相等。
//成功:1, 失败:0。
char  CommitPaidSuccess(uint curpage/*当前页地址*/, 
	  	uchar curBlockIndex/*当前页内字节块的索引号*/, uchar *szBytes, uchar num)
{
 	  char  cByteNum = 0;
	  uchar CmpData[20];
	  
	  //先写入当前的记录
	  for (cByteNum = 0; cByteNum<20; cByteNum++)
	  {
	   	  	SPI_WritePageCtx(curpage, curBlockIndex*20+cByteNum, *szBytes++);
	  }
	  
	  //再读出当前消费记录
	  for (cByteNum = 0; cByteNum<20; cByteNum++)
	  {
	   	  	CmpData[cByteNum] = SPI_ReadPageCtx(curpage, curBlockIndex*20+cByteNum);
	  }
	  
	  cByteNum = memcmp((void *)szBytes, (void *)CmpData, 20);
	  
 	  return cByteNum == 0;
}

//读出前次消费记录的待写FLASH页地址和页内字节地址。
void  GetHistoryPageAndBytesAddr(uint *oldpage, uint *oldByteAddr)
{
      uchar  cData = 0;
      
 	  *oldpage = SPI_ReadPageCtx(0, 0);
	  cData = SPI_ReadPageCtx(0, 1);
	  
	  *oldpage     = *oldpage*256;
	  *oldpage     += cData;
	  
	  *oldByteAddr = SPI_ReadPageCtx(0, 2);
}

//计算出下次消费记录的待写FLASH页地址和页内字节地址。
//注意忽略每页的后4个字节,只考虑使用前260个字节,每条记录20个字节。
void  CalcNextPageAndBytesAddr(uint oldpage, uint oldByteAddr, uint *newPage, 
	  							uint *newByteAddr)
{
 	  *newByteAddr = oldByteAddr +1;
      *newPage     = oldpage;
	  
	  if (*newByteAddr > 12) //换页时
	  {
	   	 *newPage  = oldpage + 1;
		 *newByteAddr = 0;
	  }
}







/******************************************************************************* 
**            与I2C通信的子程序 
*******************************************************************************/
void i2cSendByte(uchar data) 
{ 
   	// 装载数据到 TWDR 
   	TWDR=data; 
   	// 发送开始 
   	TWCR = (TWCR&0x0F)|(1<<TWINT); 
}

// 发送开始信号
void i2cSendStart(void) 
{   
 	TWCR = (TWCR&0x0F)|(1<<TWINT)|(1<<TWSTA); 
}

// 发送停止信号
void i2cSendStop(void) 
{ 
    TWCR = (TWCR&0x0F)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO); 
}

// 产生应答信号否
void i2cAckSignal(uchar ackFlag) 
{ 
   if( ackFlag )
       TWCR = (TWCR&0x0F)|(1<<TWINT)|(1<<TWEA); 
   else
       TWCR = (TWCR&0x0F)|(1<<TWINT);
}

//向I2C器件发送字符串
void I2C_SendInfo(uchar wsla, uchar suba, uchar *szBuff, uchar num)
{
     I2cSendData[0] = wsla;
	 I2cSendData[1] = suba;
	 if (num > 0)
	 memcpy((void *)&I2cSendData[2], (void *)szBuff, num);
	 
     I2cSendDataLength = num+1;
     I2cSendDataIndex  = 0;	 //从从地址开始计算
     
	 //启动I2C传送
	 i2cSendStart();
}

//向I2C器件发送字符串
void I2C_RecvInfo(uchar wsla, uchar suba, uchar *szBuff, uchar num)
{
     I2cSendData[0] = wsla;
	 I2cSendData[1] = suba;
	 
	 //接收功能的变量
     I2cReceiveDataLength = num;
     I2cReceiveDataIndex  = 0;	 //从0开始计算
	 
	 //发送命令的变量
     I2cSendDataIndex     = 0;   //专为子地址才有此代码
	 I2cSendDataLength    = 1;	 
	 gbi2cSendByteStatus  = FALSE;
	 
	 //先启动I2C传送写从地址和子地址
	 i2cSendStart();
	 
	 //再重启I2C传送,仅写从地址
	 while(!gbi2cSendByteStatus); //等到已发送子地址后,可以接收数据
	 
	 I2cSendData[0] = wsla+1;
	 i2cSendStart();
}

//向ZLG7290发送单个字节
void Zlg7290_SendChar(uchar SegNo, uchar cByte)
{
     I2C_SendInfo(WriteZlg7290Addr, DPRAM0+SegNo, &cByte, 1);
}

//从ZLG7290读取单个字节
uchar Zlg7290_ReadKey(void)
{
     gbi2cRecvByteStatus = FALSE;
	 
     //需从键值寄存器读取哪个键被按下
     I2C_RecvInfo(WriteZlg7290Addr, 0x01, 0, 1);
	 
	 //等到接收到回应
	 while (!gbi2cRecvByteStatus && I2cReceiveDataIndex < 1);
	 
	 return I2cReceiveData[0];
}

//向M41T0发送多个字节,此处为时间(格式为:秒-分-小时-星期-日-月-年-控制字)
void M41T0_SendInfo(uchar *szData, uchar num)
{ 
     I2C_SendInfo(WriteM41T0Addr, 0/*从秒开始*/, szData, num);
}

//从M41T0读取多个字节,此处为时间(格式为:秒-分-小时-星期-日-月-年-控制字)
void M41T0_ReadInfo(uchar *szData, uchar num)
{
     if (num != 8)
	   return;
     
     gbi2cRecvByteStatus = FALSE;
	 
     //需从寄存器读取时间
     I2C_RecvInfo(WriteM41T0Addr, 0x0/*从秒开始*/, 0/*忽略*/, 8);
	 
	 //等到接收到回应
	 while (!gbi2cRecvByteStatus && I2cReceiveDataIndex < 8);
	 
	 memcpy((void *)szData, (void *)I2cReceiveData, num);     
}









/**********************************************************************

⌨️ 快捷键说明

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