📄 mm36sb020.c
字号:
/*
综述:
该程序为 MEGAWIN 公司的 mm36sb020 2Mb FLASH 存储芯片读写程序
该产品采用SPI通讯协议
特性、注意:
本程序 FLASH 操作部分为独立的功能模块,互不影响,可自行搭配使用
执行每个基本功能前均需复位:
擦除、从存储器中读取并连续读取、读到缓存、写到缓存并连续写、写到页
mm36sb020_test () 函数体提供对芯片的测试(复位并检测是否忙)
FLASH 芯片采用两线制,需要 BUSY 引脚。两线上需加上拉电阻,将默认电平拉到高
在主程序初始化时应调用 initiate_mm36sb020 进行初始化,如:
mm36sb020_OE_tris = 1;
initiate_mm36sb020 (); // 初始化
本程序完全不考虑 OE ,可自行在主程序中对FLASH操作前添加,如:
mm36sb020_OE_tris = 1;
if (!mm36sb020_OE) return (FALSE);
mm36sb020_OE_lat = 0;
mm36sb020_OE_tris = 0;
initiate_mm36sb020 ();
if (mm36sb020_test() == FALSE) return (FALSE); // 如FLASH无响应,返回
mm36sb020_reset();
……………………
对FLASH存储器的所有操作完成后应执行mm36sb020_test (),将芯片复位
操作完毕后应释放所有资源,如:
mm36sb020_test ();
initiate_mm36sb020 ();
mm36sb020_OE_tris = 1;
……………………
本程序需要定义主时钟
成功调试环境:MCU主频16MHz,18F448,MPLAB C18 Student-Edition Compiler 2.40
本程序不涉及中断,采用等待延时,失败后只返回错误
本程序中延时部分须注意看门狗复位
接口、说明:
由于编译器不稳定,本程序需外部调用的函数传参部分大于int型的量使用指针传送,并一律返回int型,请注意
本程序调用 initiate_mm36sb020 进行初始化,返回正常
调用mm36sb020_write_nbytes 实现写n个字节。(1<=n<=16)
调用mm36sb020_read_nbytes 实现读n个字节。(1<=n<=255)
这两个函数限制很大,使用时需小心
需要定义(默认在 ..\Resources.h 中):
#define MainOSC 4 // 主频(1-16Mhz),4MHz
#define TRUE 1 // 真
#define FALSE -1 // 假
#define mm36sb020_OE_tris TRISCbits.TRISC0 // FLASH 芯片
#define mm36sb020_OE_lat LATCbits.LATC0 // mm36sb020
#define mm36sb020_OE PORTCbits.RC0 // OE 引脚定义
#define mm36sb020_BUSY_tris TRISCbits.TRISC1 // BUSY
#define mm36sb020_BUSY PORTCbits.RC1 // 引脚定义
#define mm36sb020_SCL_tris TRISCbits.TRISC6 // SCL
#define mm36sb020_SCL_lat LATCbits.LATC6 // 引脚定义
#define mm36sb020_SDA_tris TRISCbits.TRISC7 //
#define mm36sb020_SDA_lat LATCbits.LATC7 // SDA
#define mm36sb020_SDA PORTCbits.RC7 // 引脚定义
*/
#include <p18cxxx.h>
#include "..\Resources.h"
#define ERSC 0x90F6 // ERaSe whole Chip
#define SRC 0xFFFFFFFE // Software Reset Chip
#define RSE 0x94 // Read Status to External
#define RBE 0x98 // Read Buffer to External
#define RME 0x9C // Read flash Memory to External
#define RMEC 0xA0 // Continusly Read Byte from Main Storage
#define RMB 0xA4 // Read page from flash Memory to Buffer
#define WEB 0xA8 // Write External data to Buffer
#define WEBC 0xAC // Continusly Write External data to Buffer
#define WBMEP 0xB0 // Write Buffer to Main Storage with Erase
#define WBMP 0xB4 // Write Buffer to Main Storage
int initiate_mm36sb020 (void); // 初始化,返回正常
int mm36sb020_test (void); // 自检测试
void mm36sb020_read_nbytes (unsigned long *, unsigned char *, unsigned char);
// 从某地址读取n字节(地址指针,最多16字节头指针, n个字节)
int mm36sb020_write_nbytes (unsigned long *, unsigned char *, unsigned char);
// 向某地址写入n字节(地址指针,最多16字节头指针, n个字节)
/* -------------- 独立基本功能模块函数声明 -------------- */
void mm36sb020_write_bits (unsigned long, unsigned char); // 写入位(命令字,长度) 内部调用
unsigned char mm36sb020_read_bits (void); // 读出位 内部调用
void mm36sb020_write_data_bits (unsigned char); // 写入位(8位命令字,快速无延时) 内部调用
void mm36sb020_reset (void); // 复位
int mm36sb020_erase (void); // 芯片擦除
int mm36sb020_read_from_memory (unsigned int *, unsigned char); // 从 flash 中读一字节(页指针,地址指针)
int mm36sb020_read_continusly (void); // 连续读取
int mm36sb020_read_to_buffer (unsigned int *); // 从 flash 中读到缓存(页指针)
void mm36sb020_write_to_buffer (unsigned char, unsigned char); // 向缓存中写一字节(地址指针,字节指针)
void mm36sb020_write_continusly (unsigned char); // 连续写入(字节指针)
int mm36sb020_write_from_buffer (unsigned int *); // 从缓存中写到 flash(页指针)
/* -------------------- 延时部分 ------------------------ */
void delay5times (void); // 延时5个指令周期
void delay25times (void); // 延时25个指令周期
void delay40us (void); // 延时40微秒多
void delay500us (void); // 延时500微秒多
void delaynms (unsigned char); // 延时n(1-250)毫秒多,注意看门狗
void delay5times (void)
{ Nop (); }
void delay25times (void)
{ delay5times (); delay5times ();
delay5times (); delay5times ();
Nop (); }
void delay40us (void)
{
unsigned char roundtimes;
roundtimes = MainOSC;
while (roundtimes!=0)
{
delay5times ();
delay5times ();
roundtimes--;
};
}
void delay500us (void)
{
unsigned char roundtimes;
roundtimes = MainOSC;
while (roundtimes!=0)
{
delay25times ();
delay25times ();
delay25times ();
delay25times ();
delay25times ();
roundtimes--;
};
}
void delaynms (unsigned char mstimes)
{
while (mstimes!=0)
{
delay500us ();
delay500us ();
mstimes--;
};
}
/* ---------------- 独立基本功能模块 -------------------- */
void mm36sb020_write_bits (unsigned long databits, unsigned char bitslength)
{ // 向 SPI 引脚写入位(命令字,长度) 内部调用
mm36sb020_SCL_tris = 1; // 预置时钟引脚为高电平
mm36sb020_SCL_lat = 0; // 时钟 lat 为低电平
mm36sb020_SDA_tris = 1; // 预置数据引脚为高电平
mm36sb020_SDA_lat = 0; // 数据 lat 为低电平
while (bitslength!=0) // 循环 bitslength 位次
{
mm36sb020_SDA_tris = databits & 0x00000001; // 由低到高顺序置 SDA 电平
mm36sb020_SCL_tris = 0; // 时钟下降沿
databits = databits >> 1; // 数据右移
delay25times ();
mm36sb020_SCL_tris = 1; // 时钟上升沿,数据移入
bitslength--; // 循环次数减一
delay25times ();
};
mm36sb020_SDA_tris = 1; // 恢复 SDA 默认状态
}
unsigned char mm36sb020_read_bits (void)
{ // 从 SPI 引脚读出位 内部调用
unsigned char received,i=8;
mm36sb020_SCL_tris = 1; // 预置时钟引脚为高电平
mm36sb020_SCL_lat = 0; // 时钟 lat 为低电平
mm36sb020_SDA_tris = 1; // 预置数据引脚为输入
while (i!=0) // 循环 8 次
{
mm36sb020_SCL_tris = 0; // 时钟引脚 下降沿
received = received >> 1; // 先收LSB,收到的字节右移一位
i--; // 循环次数减一
mm36sb020_SCL_tris = 1; // 时钟引脚 上升沿,数据移出
Nop ();
if (mm36sb020_SDA) // 判断高低电平:
{ received |= 0x80; } // 为高(1)
else
{ received |= 0x00; }; // 为低(0)
};
return (received); // 返回收到的字节
}
void mm36sb020_write_data_bits (unsigned char databits)
{ // 向 SPI 引脚写入位(8位命令字,无延时) 内部调用
unsigned char i=8;
mm36sb020_SCL_tris = 1; // 预置时钟引脚为高电平
mm36sb020_SCL_lat = 0; // 时钟 lat 为低电平
mm36sb020_SDA_tris = 1; // 预置数据引脚为高电平
mm36sb020_SDA_lat = 0; // 数据 lat 为低电平
while (i!=0) // 循环 8 位次
{
mm36sb020_SDA_tris = databits & 0x01; // 由低到高顺序置 SDA 电平
mm36sb020_SCL_tris = 0; // 时钟下降沿
databits = databits >> 1; // 数据右移
mm36sb020_SCL_tris = 1; // 时钟上升沿,数据移入
i--; // 循环次数减一
};
mm36sb020_SDA_tris = 1; // 恢复 SDA 默认状态
}
void mm36sb020_reset (void)
{ // 复位
mm36sb020_write_bits (SRC,32); // 发送32位的复位命令
}
int mm36sb020_erase (void)
{ // 芯片擦除
mm36sb020_write_bits (ERSC,16); // 发送16位的擦除命令
delay25times ();
mm36sb020_SCL_tris = 0; // 时钟下降沿,执行擦除命令
delay5times ();
mm36sb020_SCL_tris = 1; // 恢复 SCL 默认状态
if (!mm36sb020_BUSY) return (FALSE); // 如 BUSY 位为零(不忙),返回错误
ClrWdt ();
delaynms (40); // 延时 35ms
ClrWdt ();
if (mm36sb020_BUSY) return (FALSE); // 如 BUSY 位不为零(忙),返回错误
return (TRUE); // 返回正常
}
int mm36sb020_read_from_memory (unsigned int *mm36sb020_page, unsigned char mm36sb020_address)
{ // 从 flash 中读一字节(页指针,地址指针)
mm36sb020_write_bits (RME,8); // 发送8位的读取命令
mm36sb020_write_bits (mm36sb020_address,8); // 发送8位的地址
mm36sb020_write_bits (*mm36sb020_page,16); // 发送16位的页号
return ( mm36sb020_read_bits() ); // 返回读到的字节
}
int mm36sb020_read_continusly (void)
{ // 接上面函数,连续读取
mm36sb020_write_data_bits (RMEC); // 发送8位的连续读取命令
return ( mm36sb020_read_bits() ); // 返回读到的字节
}
int mm36sb020_read_to_buffer (unsigned int *mm36sb020_page)
{ // 从 flash 中读到缓存(页指针)
mm36sb020_write_bits (RMB,8); // 发送8位的读取命令
mm36sb020_write_bits (*mm36sb020_page,16); // 发送16位的页号
delay25times ();
mm36sb020_SCL_tris = 0; // 时钟下降沿,执行读取命令
delay5times ();
mm36sb020_SCL_tris = 1; // 恢复 SCL 默认状态
if (!mm36sb020_BUSY) return (FALSE); // 如 BUSY 位为零(不忙),返回错误
delay40us ();
delay40us (); // 延时 70us
if (mm36sb020_BUSY) return (FALSE); // 如 BUSY 位不为零(忙),返回错误
return (TRUE); // 返回正常
}
void mm36sb020_write_to_buffer (unsigned char mm36sb020_address, unsigned char databyte)
{ // 向缓存中写一字节(地址指针,字节指针)
mm36sb020_write_bits (WEB,8); // 发送8位的写入命令
mm36sb020_write_bits (mm36sb020_address,8); // 发送8位的地址
mm36sb020_write_bits (databyte,8); // 发送8位的写入数据
}
void mm36sb020_write_continusly (unsigned char databyte)
{ // 接上面函数,连续写入
mm36sb020_write_bits (WEBC,8); // 发送8位的连续写入命令
mm36sb020_write_bits (databyte,8); // 发送8位的写入数据
}
int mm36sb020_write_from_buffer (unsigned int *mm36sb020_page)
{ // 从缓存中写到 flash(页指针)
mm36sb020_write_bits (WBMEP,8); // 发送8位的写入命令
mm36sb020_write_bits (*mm36sb020_page,16); // 发送16位的页号
delay25times ();
mm36sb020_SCL_tris = 0; // 时钟下降沿,执行写入命令
delay5times ();
mm36sb020_SCL_tris = 1; // 恢复 SCL 默认状态
if (!mm36sb020_BUSY) return (FALSE); // 如 BUSY 位为零(不忙),返回错误
ClrWdt ();
delaynms (15); // 延时 12ms
if (mm36sb020_BUSY) return (FALSE); // 如 BUSY 位不为零(忙),返回错误
return (TRUE); // 返回正常
}
/* ------------------------------------------------------ */
int mm36sb020_test (void)
{ // 自检测试
mm36sb020_reset (); // 复位
delay25times ();
mm36sb020_SCL_tris = 0; // 时钟下降沿,执行复位命令
delay5times ();
mm36sb020_SCL_tris = 1; // 恢复 SCL 默认状态
if (!mm36sb020_BUSY) return (FALSE); // 如 BUSY 位为零(不忙),返回错误
delay40us (); // 延时 32us
if (mm36sb020_BUSY) return (FALSE); // 如 BUSY 位不为零(忙),返回错误
return (TRUE); // 返回正常
}
int initiate_mm36sb020 (void)
{
mm36sb020_BUSY_tris = 1; // BUSY 置为输入
mm36sb020_SCL_lat = 0; // 时钟 lat 为低电平
mm36sb020_SDA_lat = 0; // 数据 lat 为低电平
mm36sb020_SCL_tris = 1; // 预置时钟引脚为默认高电平
mm36sb020_SDA_tris = 1; // 预置数据引脚为默认高电平
return (TRUE); // 返回正常
}
void mm36sb020_read_nbytes (unsigned long *mm36sb020_whole_address, unsigned char *data_pointer, unsigned char n)
{ // 从某地址读取n字节(地址指针,最多16字节头指针, n个字节)
unsigned int page;
unsigned char num,i;
page = (*mm36sb020_whole_address)/0x80; // 求出页号
num = (*mm36sb020_whole_address % 0x80) & 0x70; // 求出页内地址
mm36sb020_reset(); // 复位
data_pointer[0] = mm36sb020_read_from_memory (&page,num); // 读取第一个字节
i=1;
while (i!=n) // n个字节
{
data_pointer[i] = mm36sb020_read_continusly (); // 连续读取n个字节
i++;
};
}
int mm36sb020_write_nbytes (unsigned long *mm36sb020_whole_address, unsigned char *data_pointer, unsigned char n)
{ // 向某地址写入n字节(地址指针,最多16字节头指针, n个字节)
unsigned int page;
unsigned char num,i;
page = (*mm36sb020_whole_address)/0x80; // 求出页号
num = (*mm36sb020_whole_address % 0x80) & 0x70; // 求出页内地址
mm36sb020_reset(); // 复位
if (mm36sb020_read_to_buffer(&page) == FALSE) return (FALSE); // 将该页读入缓存
mm36sb020_reset(); // 复位
mm36sb020_write_to_buffer (num,data_pointer[0]);
i=1;
while (i!=n) // n个字节
{
mm36sb020_write_continusly (data_pointer[i]); // 字节递加
i++;
}; // 将n个字节写入缓存
mm36sb020_reset(); // 复位
if (mm36sb020_write_from_buffer(&page) == FALSE) return (FALSE); // 将缓存回写入该页
return (TRUE); // 返回正常
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -