📄 main.c
字号:
/**********************************************************************************************************
陕 西 ?? 电 子 有 限 公 司
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 + -