网站建设案例分析,国内权重网站排名,什么网站可以免费发布招聘信息,苏州保洁公司电话号码STC15系列单片机通过串口多字节数据读写EEPROM操作#x1f4cc;相关篇《STC15系列单片机EEPROM读写示例》
⛳手册勘误信息注意事项 ⚡在手册上面描述STC15F2K60S2及STC15L2K60S2系列单片机内部EEPROM还可以用MOVC指令读#xff0c;但此时首地址不再是0000H#xff0c;而是程…STC15系列单片机通过串口多字节数据读写EEPROM操作 相关篇《STC15系列单片机EEPROM读写示例》
⛳手册勘误信息注意事项 ⚡在手册上面描述STC15F2K60S2及STC15L2K60S2系列单片机内部EEPROM还可以用MOVC指令读但此时首地址不再是0000H而是程序存储空间结束地址的下一个地址。实际上STC15F2K60S2型号单片机验证时发现EEPROM起始扇区首地址0x0000 - 0x0200 2个扇区1K512X2而不是像手册上描述的在CODE区后面的2个扇区。⚡对于IAP型号的单片机EEPROM扇区在CODE程序区后面。 例如上面的程序编译信息可以得知程序所占用的容量code551转换为扇区就是需要占用2个扇区2 X 512对于IAP单片机整个ROM区都可以作为eeprom使用在不覆盖程序的情况下从第3扇区作为eeprom的首地址0x600。 STC15系列单片机通过串口读写EEPROM示例
✨这里以 STC15F2K60S2为烧录对象为例。采用22.1184MHz波特率115200程序代码
/*---------------------------------------------------------------------*/
/* --- STC MCU International Limited ----------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.GXWMCU.com --------------------------------------------*/
/* --- QQ: 800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了宏晶科技的资料及程序 */
/*---------------------------------------------------------------------*//************* 本程序功能说明 **************测试说明通过串口对STC内部自带的EEPROM(FLASH)进行读写测试。对FLASH做扇区擦除、写入、读出的操作命令指定地址。默认波特率: 115200,8,N,1.
默认主时钟: 22118400HZ.串口命令设置: (命令字母不区分大小写)W 0x8000 1234567890 -- 对0x8000地址写入字符1234567890.R 0x8000 10 -- 对0x8000地址读出10个字节数据. 注意为了通用程序不识别地址是否有效用户自己根据具体的型号来决定。******************************************/#define MAIN_Fosc 22118400L //定义主时钟
#include STC15Fxxxx.H#define Baudrate1 115200L
#define Tmp_Length 70 //读写EEPROM缓冲长度#define UART1_BUF_LENGTH (Tmp_Length9) //串口缓冲长度u8 RX1_TimeOut;
u8 TX1_Cnt; //发送计数
u8 RX1_Cnt; //接收计数
bit B_TX1_Busy; //发送忙标志u8 xdata RX1_Buffer[UART1_BUF_LENGTH]; //接收缓冲
u8 xdata tmp[Tmp_Length]; //EEPROM操作缓冲void UART1_config(u8 brt); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
void PrintString1(u8 *puts);
void UART1_TxByte(u8 dat);
void delay_ms(u8 ms);
u8 CheckData(u8 dat);
u16 GetAddress(void);
u8 GetDataLength(void);
void EEPROM_SectorErase(u16 EE_address);
void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 length);
u8 EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length);/********************* 主函数 *************************/
void main(void)
{u8 i,j;u16 addr;u8 status;P0M1 0; P0M0 0; //设置为准双向口P1M1 0; P1M0 0; //设置为准双向口P2M1 0; P2M0 0; //设置为准双向口P3M1 0; P3M0 0; //设置为准双向口P4M1 0; P4M0 0; //设置为准双向口P5M1 0; P5M0 0; //设置为准双向口P6M1 0; P6M0 0; //设置为准双向口P7M1 0; P7M0 0; //设置为准双向口UART1_config(1); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.EA 1; //允许总中断PrintString1(STC15F2K60S2系列单片机EEPROM测试程序, 串口命令设置如下示例:\r\n); //SUART1发送一个字符串PrintString1(W 0x8000 1234567890 -- 对0x8000地址写入字符1234567890.\r\n); //SUART1发送一个字符串PrintString1(R 0x8000 10 -- 对0x8000地址读出10个字节数据.\r\n); //SUART1发送一个字符串while(1){delay_ms(1);if(RX1_TimeOut 0) //超时计数{if(--RX1_TimeOut 0){// for(i0; iRX1_Cnt; i) UART1_TxByte(RX1_Buffer[i]); //把收到的数据原样返回,用于测试status 0xff; //状态给一个非0值if((RX1_Cnt 10) (RX1_Buffer[1] ) (RX1_Buffer[8] )) //最短命令为10个字节{for(i0; i8; i){if((RX1_Buffer[i] a) (RX1_Buffer[i] z)) RX1_Buffer[i] RX1_Buffer[i] - a A; //小写转大写}addr GetAddress();if(addr 63488) //限制在0~123扇区{if(RX1_Buffer[0] W) //写入N个字节{j RX1_Cnt - 9;if(j Tmp_Length) j Tmp_Length; //越界检测EEPROM_SectorErase(addr); //擦除扇区i EEPROM_write_n(addr,RX1_Buffer[9],j); //写N个字节if(i 0){PrintString1(已写入);if(j 100) {UART1_TxByte(j/1000); j j % 100;}if(j 10) {UART1_TxByte(j/100); j j % 10;}UART1_TxByte(j%100);PrintString1(字节数据!\r\n);}else PrintString1(写入错误!\r\n);status 0; //命令正确}else if(RX1_Buffer[0] R) //PC请求返回N字节EEPROM数据{j GetDataLength();if(j Tmp_Length) j Tmp_Length; //越界检测if(j 0){PrintString1(读出);UART1_TxByte(j/100);UART1_TxByte(j%100);PrintString1(个字节数\xfd据如下\r\n);EEPROM_read_n(addr,tmp,j);for(i0; ij; i) UART1_TxByte(tmp[i]);UART1_TxByte(0x0d);UART1_TxByte(0x0a);status 0; //命令正确}}}}if(status ! 0) PrintString1(命令错误!\r\n);RX1_Cnt 0; //清除字节数}}}
}
////
// 函数: void delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//
void delay_ms(u8 ms)
{unsigned int i;do{i MAIN_Fosc / 14000;while(--i) ; //14T per loop}while(--ms);
}//
// 函数: u8 CheckData(u8 dat)
// 描述: 将字符0~9,A~F或a~f转成十六进制.
// 参数: dat: 要检测的字符.
// 返回: 0x00~0x0F为正确. 0xFF为错误.
// 版本: V1.0, 2012-10-22
//
u8 CheckData(u8 dat)
{if((dat 0) (dat 9)) return (dat-0);if((dat A) (dat F)) return (dat-A10);return 0xff;
}//
// 函数: u16 GetAddress(void)
// 描述: 计算各种输入方式的地址.
// 参数: 无.
// 返回: 16位EEPROM地址.
// 版本: V1.0, 2013-6-6
//
u16 GetAddress(void)
{u16 address;u8 i,j;address 0;if((RX1_Buffer[2] 0) (RX1_Buffer[3] X)){for(i4; i8; i){j CheckData(RX1_Buffer[i]);if(j 0x10) return 65535; //erroraddress (address 4) j;}return (address);}return 65535; //error
}/**************** 获取要读出数据的字节数 ****************************/
u8 GetDataLength(void)
{u8 i;u8 length;length 0;for(i9; iRX1_Cnt; i){if(CheckData(RX1_Buffer[i]) 10) break;length length * 10 CheckData(RX1_Buffer[i]);}return (length);
}//
// 函数: void PrintString1(u8 *puts)
// 描述: 串口1发送字符串函数。
// 参数: puts: 字符串指针.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//
void PrintString1(u8 *puts) //发送一个字符串
{for (; *puts ! 0; puts) UART1_TxByte(*puts); //遇到停止符0结束
}//
// 函数: SetTimer2Baudraye(u16 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//
void SetTimer2Baudraye(u16 dat) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{AUXR ~(14); //Timer stopAUXR ~(13); //Timer2 set As TimerAUXR | (12); //Timer2 set as 1T modeTH2 dat / 256;TL2 dat % 256;IE2 ~(12); //禁止中断AUXR | (14); //Timer run enable
}//
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//
void UART1_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{/*********** 波特率使用定时器2 *****************/if(brt 2){AUXR | 0x01; //S1 BRT Use Timer2;SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / Baudrate1);}/*********** 波特率使用定时器1 *****************/else{TR1 0;AUXR ~0x01; //S1 BRT Use Timer1;AUXR | (16); //Timer1 set as 1T modeTMOD ~(16); //Timer1 set As TimerTMOD ~0x30; //Timer1_16bitAutoReload;TH1 (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) / 256);TL1 (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) % 256);ET1 0; //禁止中断INT_CLKO ~0x02; //不输出时钟TR1 1;}/*************************************************/SCON (SCON 0x3f) | 0x40; //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
// PS 1; //高优先级中断ES 1; //允许中断REN 1; //允许接收P_SW1 0x3f;P_SW1 | 0x00; //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7 (必须使用内部时钟)
// PCON2 | (14); //内部短路RXD与TXD, 做中继, ENABLE,DISABLEB_TX1_Busy 0;TX1_Cnt 0;RX1_Cnt 0;RX1_TimeOut 0;
}//
// 函数: void UART1_TxByte(u8 dat)
// 描述: 发送一个字节.
// 参数: 无.
// 返回: 无.
// 版本: V1.0, 2014-6-30
//void UART1_TxByte(u8 dat)
{SBUF dat;B_TX1_Busy 1;while(B_TX1_Busy);
}//
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//
void UART1_int (void) interrupt UART1_VECTOR
{if(RI){RI 0;if(RX1_Cnt UART1_BUF_LENGTH) RX1_Cnt 0;RX1_Buffer[RX1_Cnt] SBUF;RX1_Cnt;RX1_TimeOut 5;}if(TI){TI 0;B_TX1_Busy 0;}
}/*
STC15F/L2KxxS2 扇区分配512字节/扇区从0x0000开始。型号 大小 扇区数 开始地址 结束地址 MOVC读偏移地址
STC15F/L2K08S2 53K 106扇区 0x0000 ~ 0xD3FF 0x2000
STC15F/L2K16S2 45K 90扇区 0x0000 ~ 0xB3FF 0x4000
STC15F/L2K24S2 37K 74扇区 0x0000 ~ 0x93FF 0x6000
STC15F/L2K32S2 29K 58扇区 0x0000 ~ 0x73FF 0x8000
STC15F/L2K40S2 21K 42扇区 0x0000 ~ 0x53FF 0xA000
STC15F/L2K48S2 13K 26扇区 0x0000 ~ 0x33FF 0xC000
STC15F/L2K56S2 5K 10扇区 0x0000 ~ 0x13FF 0xE000
STC15F/L2K60S2 1K 2扇区 0x0000 ~ 0x03FF 0xF000STC15F/L2K61S2 无EPROM, 整个122扇区的FLASH都可以擦写 地址 0x0000~0xF3ff.
*/#define ISP_ENABLE() ISP_CONTR (ISP_EN ISP_WAIT_FREQUENCY)
#define ISP_DISABLE() ISP_CONTR 0; ISP_CMD 0; ISP_TRIG 0; ISP_ADDRH 0xff; ISP_ADDRL 0xff//
// 函数: void DisableEEPROM(void)
// 描述: 禁止EEPROM.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2014-6-30
//
void DisableEEPROM(void) //禁止访问EEPROM
{ISP_CONTR 0; //禁止ISP/IAP操作ISP_CMD 0; //去除ISP/IAP命令ISP_TRIG 0; //防止ISP/IAP命令误触发ISP_ADDRH 0xff; //指向非EEPROM区防止误操作ISP_ADDRL 0xff; //指向非EEPROM区防止误操作
}//
// 函数: void EEPROM_Trig(void)
// 描述: 触发EEPROM操作.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2014-6-30
//
void EEPROM_Trig(void)
{F0 EA; //保存全局中断EA 0; //禁止中断, 避免触发命令无效ISP_TRIG(); //先送5AH再送A5H到ISP/IAP触发寄存器每次都需要如此//送完A5H后ISP/IAP命令立即被触发启动//CPU等待IAP完成后才会继续执行程序。_nop_();_nop_();EA F0; //恢复全局中断
}//
// 函数: void EEPROM_SectorErase(u16 EE_address)
// 描述: 擦除一个扇区.
// 参数: EE_address: 要擦除的EEPROM的扇区中的一个字节地址.
// 返回: none.
// 版本: V1.0, 2014-6-30
//
void EEPROM_SectorErase(u16 EE_address)
{ISP_ENABLE(); //设置等待时间允许ISP/IAP操作送一次就够IAP_CONTR 0X83;ISP_ERASE(); //宏调用, 送扇区擦除命令命令不需改变时不需重新送命令//只有扇区擦除没有字节擦除512字节/扇区。//扇区中任意一个字节地址都是扇区地址。ISP_ADDRH EE_address / 256; //送扇区地址高字节地址需要改变时才需重新送地址ISP_ADDRL EE_address % 256; //送扇区地址低字节EEPROM_Trig(); //触发EEPROM操作DisableEEPROM(); //禁止EEPROM操作
}//
// 函数: void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 lenth)
// 描述: 读N个字节函数.
// 参数: EE_address: 要读出的EEPROM的首地址.
// DataAddress: 要读出数据的指针.
// length: 要读出的长度
// 返回: 0: 写入正确. 1: 写入长度为0错误. 2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//
void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 length)
{ISP_ENABLE(); //设置等待时间允许ISP/IAP操作送一次就够IAP_CONTR 0X83;ISP_READ(); //送字节读命令命令不需改变时不需重新送命令do{ISP_ADDRH EE_address / 256; //送地址高字节地址需要改变时才需重新送地址ISP_ADDRL EE_address % 256; //送地址低字节EEPROM_Trig(); //触发EEPROM操作*DataAddress ISP_DATA; //读出的数据送往EE_address;DataAddress;}while(--length);DisableEEPROM();
}//
// 函数: u8 EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length)
// 描述: 写N个字节函数.
// 参数: EE_address: 要写入的EEPROM的首地址.
// DataAddress: 要写入数据的指针.
// length: 要写入的长度
// 返回: 0: 写入正确. 1: 写入长度为0错误. 2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//
u8 EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length)
{u8 i;u16 j;u8 *p;if(length 0) return 1; //长度为0错误ISP_ENABLE(); //设置等待时间允许ISP/IAP操作送一次就够i length;j EE_address;p DataAddress;ISP_WRITE(); //宏调用, 送字节写命令do{ISP_ADDRH EE_address / 256; //送地址高字节地址需要改变时才需重新送地址ISP_ADDRL EE_address % 256; //送地址低字节ISP_DATA *DataAddress; //送数据到ISP_DATA只有数据改变时才需重新送EEPROM_Trig(); //触发EEPROM操作EE_address; //下一个地址DataAddress; //下一个数据}while(--length); //直到结束EE_address j;length i;DataAddress p;i 0;ISP_READ(); //读N个字节并比较do{ISP_ADDRH EE_address / 256; //送地址高字节地址需要改变时才需重新送地址ISP_ADDRL EE_address % 256; //送地址低字节EEPROM_Trig(); //触发EEPROM操作if(*DataAddress ! ISP_DATA) //读出的数据与源数据比较{i 2;break;}EE_address;DataAddress;}while(--length);DisableEEPROM();return i;
}
串口写入和读取操作
写入操作W 0x0200 abcd9527 读取操作R 0x0200 14 在第一个扇区写入数据W 0x0000 去年今日此门中人面桃花相映红。人面不知何处去桃花依旧笑春风。 读取第一个扇区数据R 0x0000 70
程序源码 本案例来源于STC实验箱4中的案例修改而来。 复制这段内容后打开百度网盘手机App操作更方便哦
链接: https://pan.baidu.com/s/1Q5k8FONsXFhnaDBcE3jiOw
提取码: dhye