

对的,你现在遇到的是编码不一致 典型场景:
VS Code → UTF-8;
MPLAB X 工程 → 默认 ISO-8859-1,所以中文全乱了。
分两步搞定:
一、把 MPLAB X 工程编码改成 UTF-8
MPLAB X 是支持 UTF-8 的,只是默认不是。官方说明:项目创建时会选一个编码,之后可以在 Project Properties → General 里修改 。(Microchip Support)
在 MPLAB X v6.25 里这样操作:
-
在 Projects 窗口 中,右键你的工程(比如
exer1.X) -
选 Properties...(工程属性)
-
在左边树里选:Conf: [default] → General
-
右侧最下面有一项:Encoding
- 默认一般是
ISO 8859-1 - 下拉选项改为
UTF-8
- 默认一般是
-
点 OK 保存
-
把已经打开的 .c/.h 文件关掉重开一次,看中文是否恢复正常
这个设置是整个工程的默认编码 ,之后 MPLAB X 读/写源码都会按 UTF-8 处理。(Microchip Docs)
二、确认源码文件本身真的是 UTF-8
如果你在 VS Code 里保存就是 UTF-8,一般没问题;
可以在 VS Code 状态栏右下角看:
- 显示
UTF-8→ OK - 如果是
GBK/GB2312/ANSI→ 需要先转换;
转换方法(在 VS Code 中):
- 打开该 .c/.h 文件
- 右下角点编码(比如
GBK) - 选 "另存为编码 / Save with Encoding..."
- 选 UTF-8
- 保存
然后回到 MPLAB X(工程编码已设置为 UTF-8),再打开这个文件,中文就不会乱了。
小结
-
必须两边统一:
- VS Code 保存:UTF-8
- MPLAB X 工程 Encoding:UTF-8
-
只改一边不行:
- 工程还是 ISO-8859-1 → UTF-8 文件照样被当成 Latin-1 来解 → 中文乱码(典型"莫名乱码/mojibake"现象)。
c
/*
* ============================================================================
* DSPIC33CK32MC105 Curiosity Nano OOB Demo 主控程序
* ----------------------------------------------------------------------------
* - 负责配置 MCU 的时钟、复位、调试与安全相关配置位
* - 初始化 UART1 以便通过 Curiosity Nano 板载调试器的 USB-CDC 输出日志
* - 通过 RB2 读取板载按钮状态,驱动 RC8 LED 并输出提示字符串
* ============================================================================
*/
// DSPIC33CK32MC105 配置位设置
// 以下 pragma config 基于 Curiosity Nano OOB Demo 推荐设置
// FSEC
#pragma config BWRP = OFF // Boot 区段写保护位(Boot 区段允许写入)
#pragma config BSS = DISABLED // Boot 区段代码保护级别位(无保护(除非设置了 BWRP))
#pragma config BSEN = OFF // Boot 区段控制位(没有 Boot 区段)
#pragma config GWRP = OFF // 通用区段写保护位(通用区段允许写入)
#pragma config GSS = DISABLED // 通用区段代码保护级别位(无保护(除非设置了 GWRP))
#pragma config CWRP = OFF // 配置区段写保护位(配置区段允许写入)
#pragma config CSS = DISABLED // 配置区段代码保护级别位(无保护(除非设置了 CWRP))
#pragma config AIVTDIS = OFF // 备用中断向量表禁用位(禁用备用中断向量表)
// FBSLIM - 设置 Boot 区段 Flash 地址上限
#pragma config BSLIM = 0x1FFF // Boot 区段 Flash 页地址上限位(输入十六进制值)
// FOSCSEL - 决定 MCU 上电后的初始振荡源
#pragma config FNOSC = FRCDIVN // 振荡源选择(内部高速 RC(FRC)振荡器,带分频器)
#pragma config IESO = ON // 双速振荡器启动使能位(先用 FRC 启动,再切换到用户选择振荡源)
// FOSC
#pragma config POSCMD = NONE // 主振荡器模式选择位(主振荡器禁用)
#pragma config OSCIOFNC = OFF // OSC2 引脚功能位(OSC2 为时钟输出)
#pragma config FCKSM = CSDCMD // 时钟切换模式位(时钟切换和故障安全时钟监控均禁用)
#pragma config PLLKEN = ON // PLL 锁定使能(如锁定丢失,则禁用 PLL 时钟输出)
#pragma config XTCFG = G3 // 晶体配置(24-32 MHz 晶体)
#pragma config XTBST = ENABLE // 晶体启动增强(增强启动,kick-start)
// FWDT
#pragma config RWDTPS = PS2147483648 // 运行模式看门狗定时器预分频选择(1:2147483648)
#pragma config RCLKSEL = LPRC // 看门狗定时器时钟选择(始终使用低功耗 RC 时钟)
#pragma config WINDIS = ON // 看门狗定时器窗口使能(非窗口模式)
#pragma config WDTWIN = WIN25 // 看门狗定时器窗口选择(窗口为 WDT 周期的 25%)
#pragma config SWDTPS = PS2147483648 // 睡眠模式看门狗定时器预分频选择(1:2147483648)
#pragma config FWDTEN = ON // 看门狗定时器使能位(硬件使能 WDT)
// FPOR
#pragma config BISTDIS = DISABLED // 内存 BIST 功能禁用(复位时 mBIST 功能禁用)
// FICD
#pragma config ICS = PGD1 // 在电路调试通道选择位(在 PGC1 和 PGD1 通道通讯)
#pragma config JTAGEN = OFF // JTAG 使能位(禁用 JTAG)
// FDMTIVTL
#pragma config DMTIVTL = 0xFFFF // Dead Man 计时器低字节区间(输入十六进制值)
// FDMTIVTH
#pragma config DMTIVTH = 0xFFFF // Dead Man 计时器高字节区间(输入十六进制值)
// FDMTCNTL
#pragma config DMTCNTL = 0xFFFF // 32 位 DMT 指令计数超时值低 16 位(输入 0-0xFFFF 十六进制值)
// FDMTCNTH
#pragma config DMTCNTH = 0xFFFF // 32 位 DMT 指令计数超时值高 16 位(输入 0-0xFFFF 十六进制值)
// FDMT
#pragma config DMTDIS = OFF // Dead Man 计时器禁用位(禁用 Dead Man 计时器,可软件使能)
// FDEVOPT
#pragma config ALTI2C1 = OFF // I2C1 备用引脚位(I2C1 映射到 SDA1/SCL1 引脚)
#pragma config SMB3EN = SMBUS3 // SMBus 使能(采用 SMBus 3.0 输入电平标准)
#pragma config SPI2PIN = PPS // SPI2 引脚选择(SPI2 使用 PPS 可重映射引脚)
// FALTREG
#pragma config CTXT1 = OFF // 分配给备用工作寄存器 1 的中断优先级(未分配)
#pragma config CTXT2 = OFF // 分配给备用工作寄存器 2 的中断优先级(未分配)
#pragma config CTXT3 = OFF // 分配给备用工作寄存器 3 的中断优先级(未分配)
#pragma config CTXT4 = OFF // 分配给备用工作寄存器 4 的中断优先级(未分配)
// #pragma config 语句应放在项目文件包含之前。
// 使用项目枚举代替 #define 来表示 ON 和 OFF。
#include <xc.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define FCY 1000000UL
#include <libpic30.h>
/*
* 功能: 初始化 UART1,用于板载调试器虚拟串口输出提示信息
* 步骤:
* 1. 清零 UART1 模块寄存器,从已知状态开始
* 2. 以 Fosc=200 MHz 计算波特率,配置为 9600 bps
* 3. 启用 TX/RX、输出使能以及 UART 模块
* 4. 通过 PPS 将 UART1 TX/RX 映射到板载调试器连接的 RD10/RD11 (RP58/RP59)
*/
void UartInit(void)
{
U1MODE = 0;
U1MODEH = 0;
U1STA = 0;
U1STAH = 0;
U1BRG = 25; // 9600 baud @ Fcy ~4 MHz (BRGH=0)
U1STAHbits.URXISEL = 6;
U1MODEHbits.BCLKSEL = 0;
U1MODEbits.UTXEN = 1;
U1MODEbits.URXEN = 1;
U1MODEbits.UARTEN = 1;
//DEBUGGER USB RX/TX TEST - FOR OOB DEMO EFFORT
RPOR13bits.RP58R = 1;
RPINR18bits.U1RXR = 59;
}
/*
* 功能: 通过轮询方式发送单个字节
* - 等待发送移位寄存器空,再写入发送寄存器
*/
void UartSendByte(char data)
{
while (U1STAbits.TRMT == 0)
{
} // wait for room in TX buffer
U1TXREG = data;
}
/*
* 功能: 发送以 '\0' 结尾的字符串
* - 遍历字符数组并逐字节发送
*/
void UartSendString(char *pData)
{
unsigned int x = 0;
while(pData[x] != 0)
{
UartSendByte(pData[x]);
x = x + 1;
}
}
int main(void)
{
/*
* data2: 设备刚上电且按钮未按下时,周期性提示用户按下按钮
* data : 检测到按钮按下后,提示 LED 将执行闪烁
* data1: 按钮释放后提示用户再次按下
*/
char data2[] = "DSPIC33CK32MC105 Curiosity Nano Demo. Please press on-board button to initiate demo.\n\r";
char data[] = "\n Button pressed! Enjoy the blink. \n\r";
char data1[] = "\n Button not pressed... please press to observe blink. \n\r";
/*
* I/O 配置:
* - RB2: 板载按钮输入,使用内部上拉保证未按下时保持高电平
* - RC8: 板载 LED 输出,由 MCU 控制亮灭
*/
_ANSELB2 = 0; //make RB2 a digital input
_CNPUB2 = 1; //turn on internal pull up for RB2
_TRISB2 = 1; //RB2 an input
_TRISC8 = 0; // make trisc8 an output
// 初始化 UART 日志接口
UartInit();
/*
* 上电欢迎阶段:
* - 持续检测按钮是否被按下
* - 若未按下,每秒向主机发送提示并点亮 LED
* - 一旦按钮被按下,跳出循环进入主逻辑
*/
while(PORTBbits.RB2 != 0)
{
UartSendString(data2);
__delay_ms(1000);
_LATC8 = 1;
}
/*
* 主循环:
* - 实现按钮→LED 的简单人机交互
* - 按钮按下: 熄灭 LED,打印 "pressed" 信息
* - 按钮松开: 点亮 LED,打印 "not pressed" 信息
* - 每个状态保持 1 秒,以便观察
*/
while(1)
{
if(PORTBbits.RB2 == 0)
{
LATCbits.LATC8 = 1;
UartSendString(data);
__delay_ms(1000);
}
else
{
LATCbits.LATC8 = 0;
UartSendString(data1);
__delay_ms(1000);
}
}
}