PIC单片机高阶实战(五):PIC32MX系列的数据存储

作为一名使用PIC单片机近三十年的工程师,我最早从PIC16F87X系列起步,逐步深入至更集成、功能更丰富的型号。在智慧农业、工业控制等实际项目中,PIC32MX 是我频繁使用的核心芯片。其丰富的外设与六串口设计,非常适合构建多通道通信与控制系统。本次我将以一款实际投产数年的核心控制板为例,控制板MCU型号为PIC32MX534F064H,详解在板子上电运行过程中MCU如何存储各种数据。

该控制板集成了以下6大功能:

1、2路RS485数据收发(可接LED屏、各种传感器、或与其他控制板通信);

2、1路UART-TTL(可接摄像头等);

3、1路4G模块数据收发(移远或中移4G模块);

4、1路LORA无线数据收发或RS485数据收发;

5、2路无源开关量输入;

6、太阳能供电(带充电管理)或直流电源直接供电;

一、 PIC32MX系列的存储器构成:程序与数据如何共存?

在8位单片机时代,程序存储器和数据存储器通常是分开的------Flash存代码,EEPROM存数据。到了PIC32MX,情况有所不同,PIC32MX的程序 Flash 和数据 Flash 是同一片物理存储 !这意味着:

  • 你的程序代码和需要保存的用户数据,共享这64KB空间
  • 数据存储必须在规划程序大小时预留出专用区域
  • 如果写入数据时覆盖了代码区,系统将立刻崩溃

我的实践: 在这款核心板中,程序代码约占用48KB,剩下的16KB划给数据存储。通过地址计算,将数据区定在0xBD00C000开始的位置。

二、数据存储读写例程:

具体配置及程序如下:

#include<p32mx534f064h.h>

复制代码
#pragma config FPLLMUL=MUL_20,FPLLIDIV=DIV_2,FPLLODIV=DIV_1,FWDTEN=OFF
复制代码
#pragma config POSCMOD=HS,FNOSC=PRIPLL,FPBDIV=DIV_1
复制代码
复制代码
#define SYS_FREQ                          (80000000L) //80M主频
复制代码
#define NVM_PROGRAM_PAGE  0xbd00c000 //定义存储数据的起始地址
复制代码
#define NVM_PAGE_SIZE               4096 //定义数据存储空间大小
复制代码
unsigned char eeprom_e2[80];
复制代码
unsigned char data_shezhi[80]
复制代码
unsigned char dres_485=1, flag_rev=0,flag_rev2=0,flag_rev3,flag_rev4,flag_rev5,flag_rev6;
复制代码
unsigned int  time_tnt,time_tnt2,time_tnt3,time_tnt4,time_tnt5,time_tnt6, ,rev_rnt=0,rev_rnt2=0,rev_rnt3,rev_rnt4,rev_rnt5,rev_rnt6,tran_rnt1=0,tran_rnt2=0,tran_rnt3,tran_rnt4,tran_rnt5,tran_rnt6;
复制代码
复制代码
unsigned char trans[200];
复制代码
unsigned char reciv[200];
复制代码
unsigned char trans2[200];
复制代码
unsigned char reciv2[200];
复制代码
unsigned char trans3[200];
复制代码
unsigned char reciv3[200];
复制代码
unsigned char trans4[200];
复制代码
unsigned char reciv4[200];
复制代码
unsigned char trans5[200];
复制代码
unsigned char reciv5[200];
复制代码
unsigned char trans6[200];
复制代码
unsigned char reciv6[200];
复制代码
void delay(unsigned int a)
复制代码
               {
复制代码
               int i,j;
复制代码
               for(i=0;i<a;i++)
复制代码
                               for(j=0;j<100;j++)
复制代码
                                              ;
复制代码
               }
复制代码
void uart_send1(unsigned char dat) //串口1发送数据
复制代码
{
复制代码
               U1STAbits.UTXEN=1;
复制代码
               U1TXREG=dat;
复制代码
               while(!U1STAbits.TRMT);
复制代码
}
复制代码
void uart_send2(unsigned char dat) //串口2发送数据
复制代码
{
复制代码
               U2STAbits.UTXEN=1;
复制代码
               U2TXREG=dat;
复制代码
               while(!U2STAbits.TRMT);
复制代码
}
复制代码
void main() {
复制代码
    unsigned int i,j; 
复制代码
                               AD1PCFG=0XFFFF;
复制代码
                               
复制代码
                               TRISB=0x0180;
复制代码
               
复制代码
                               PORTB=0x0000;
复制代码
                               TRISC=0;
复制代码
                               PORTC=0x0000;
复制代码
                               TRISD=0x0204;
复制代码
                               PORTD=0x0000;
复制代码
                               TRISE=0x0000;
复制代码
                               PORTE=0x0000;
复制代码
                               TRISF=0x0010;
复制代码
                               PORTF=0x0000;
复制代码
                               TRISG=0x0280;
复制代码
                               PORTG=0x0000;
复制代码
                               DDPCON = 0x00 ;  //关闭EJTAG口,
复制代码
                               OSCCON&=0xfffd;
复制代码
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
复制代码
ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_5 | T1_INT_SUB_PRIOR_1);
复制代码
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
复制代码
UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
复制代码
                           UARTConfigure(UART1, UART_ENABLE_HIGH_SPEED|UART_ENABLE_PINS_TX_RX_ONLY);
复制代码
                           UARTSetDataRate(UART1, SYS_FREQ,9600);
复制代码
                           UARTSetFifoMode(UART1, UART_INTERRUPT_ON_RX_NOT_EMPTY);
复制代码
复制代码
                           ConfigIntUART1(UART_RX_INT_EN | UART_INT_PR6 | UART_INT_SUB_PR2);
复制代码
                           EnableIntU1RX;
复制代码
                           UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
复制代码
复制代码
                           UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
复制代码
                           UARTConfigure(UART2, UART_ENABLE_HIGH_SPEED|UART_ENABLE_PINS_TX_RX_ONLY);
复制代码
                           UARTSetDataRate(UART2, SYS_FREQ, 115200);
复制代码
                           UARTSetFifoMode(UART2, UART_INTERRUPT_ON_RX_NOT_EMPTY);
复制代码
复制代码
                           ConfigIntUART2(UART_RX_INT_EN | UART_INT_PR6 | UART_INT_SUB_PR2);
复制代码
                           EnableIntU2RX;
复制代码
                           UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
复制代码
复制代码
                           
复制代码
//其他初始化
复制代码
INTEnableInterrupts();
复制代码
                           OpenTimer1(T1_ON | T1_PS_1_1 | T1_SOURCE_INT,4000); //分频设置为1
复制代码
delay(10000);
复制代码
for(i=0;i<j;i++) //读取存储的数据
复制代码
                               {
复制代码
                                              eeprom_e2[i]=*(int *)(NVM_PROGRAM_PAGE + (i*4));
复制代码
                                              
复制代码
                               }
复制代码
//处理读取的数据
复制代码
while(1) {
复制代码
if(条件满足)
复制代码
{       
复制代码
               NVMErasePage((void *)NVM_PROGRAM_PAGE);
复制代码
                                                                                                           for(i=0;i<j;i++)
复制代码
                                                                                                        {
复制代码
                                                                                                     NVMWriteWord((void*)(NVM_PROGRAM_PAGE + (i*4)), data_shezhi[i]);//保存设置的数据 
复制代码
                                                                                                        }
复制代码
复制代码
}
复制代码
 // 主循环,可加入其他任务
复制代码
      
复制代码
    }
复制代码
}
复制代码
void __ISR(_UART1_VECTOR, IPL6SOFT) IntUart1Handler(void)
{
if (INTGetFlag(INT_SOURCE_UART_RX(UART1)))
{
recivrev_rnt=UARTGetDataByte(UART1);
rev_rnt+=1;
time_tnt=0;
flag_rev=1;
}
INTClearFlag(INT_SOURCE_UART_RX(UART1));
}
void __ISR(_UART2_VECTOR, IPL6SOFT) IntUart2Handler(void)
{
if (INTGetFlag(INT_SOURCE_UART_RX(UART2)))
{
reciv2rev_rnt2=tmp2=UARTGetDataByte(UART2);
rev_rnt2+=1;
time_tnt2=0;
flag_rev2=1;
}
INTClearFlag(INT_SOURCE_UART_RX(UART2));
}
void __ISR(_TIMER_1_VECTOR, ipl5) _Timer1Handler(void)
{
// DisableIntT1;
if(flag_rev==1)
{
time_tnt+=1; //1570约为06ms
}
if(flag_rev2==1)
{
time_tnt2+=1; //1570约为06ms
}
INTClearFlag(INT_T1);//中断标志清零
// EnableIntT1;
}
三、本系列文章规划

本文是《PIC单片机高阶实战》系列的第五篇,共有以下内容:

|----|-------------------|-----------------|
| 序号 | 主题 | 内容概要 |
| 1 | 振荡器与定时器 | 时钟配置与定时中断 |
| 2 | UART 通信 | 串口配置、波特率转换、数据透传 |
| 3 | I/O 按键输入 | 电平变化中断 |
| 4 | 4G 模块数据收发 | AT指令控制、4G模块数据透传 |
| 5 | 数据存储 | 数据存储与读取 |

PIC 单片机入门实战》共 8 篇文章与《 PIC 单片机进阶实战》共 6 篇文章与《 PIC 单片机高阶实战》 5 篇内容来源于我自己画的电路原理图及程序,有对 PIC 单片机感兴趣想学习的朋友可以关注我,免费赠送资料(包括原理图、数据手册、各种例程等)。

有需要这款开发板的朋友也可以关注联系我。

后续干货不断,咱们一起在单片机的世界里,共同进步。

相关推荐
周洲08302 小时前
STM32 最简工程搭建|标准库/HAL库规范化模板,零冗余可直接落地
stm32·单片机·嵌入式硬件
ACP广源盛139246256733 小时前
M6/M5 Pro Mac mini 端侧 AI 落地@ACP#YLB3116 中端多盘存储扩展在 AI 服务中的机会与应用场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos
ACP广源盛139246256734 小时前
M6/M5 Pro Mac mini 端侧 AI 新形态@ACP#GSV5800 Serdes 长距离视频传输在 AI 服务中的机会与落地场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos·音视频
D_codingXuChu4 小时前
2026物联网应用开发服务商:D-coding定制开发指南
物联网·开发经验·d-coding
OIDCAT5 小时前
国产USB转千兆网卡芯片CH398-RTL8153国产替代实测与选型
网络·嵌入式硬件·智能硬件·国产芯片·usb转千兆网卡
HRTOS6 小时前
HRTOS 4.0 驱动库:06_Storage 存储设备驱动——24C02 EEPROM与I²C驱动开发
c语言·驱动开发·嵌入式硬件·51单片机
周洲08306 小时前
STM32 串口不定长接收|空闲中断 IDLE 方案,无固定帧长限制,项目实战
stm32·单片机·嵌入式硬件
我和头发拼了9 小时前
STM32--10硬件读写MPU6050
stm32·单片机·嵌入式硬件
糖糖单片机设计10 小时前
基于STM32的鱼缸水质检测系统
stm32·单片机·嵌入式硬件
HRTOS10 小时前
HRTOS 4.0 正式发布:Driver Library 基础外设驱动模块介绍
驱动开发·单片机·嵌入式硬件·51单片机