PIC32MZ tutorial -- Hello World
Today I implement "Hello World" on PIC32MZ EC starter kit. The application of "Hello World" only lights up a LED. There are three LEDs on the starter kit board -- LED1 and LED2 and LED3. At the moment, I only light LED1 on RH0.
Every PIC application has to set several configuration bits, PIC32 is no exception. So we start with configuration bits. The following is the configuration bits I set for the "Hello world" application.
// PIC32MZ2048ECH144 Configuration Bit Settings // 'C' source line config statements #include <xc.h> // DEVCFG3 BFFFFFFF // USERID = No Setting #pragma config FMIIEN = ON // Ethernet RMII/MII Enable (MII Enabled) // in MII Mode, you need a 25MHz XTAL, in RMII Mode, need a 50MHz Clock. #pragma config FETHIO = ON // Ethernet I/O Pin Select (Default Ethernet I/O) #pragma config PGL1WAY = ON // Permission Group Lock One Way Configuration (Allow only one reconfiguration) #pragma config PMDL1WAY = ON // Peripheral Module Disable Configuration (Allow only one reconfiguration) #pragma config IOL1WAY = ON // Peripheral Pin Select Configuration (Allow only one reconfiguration) #pragma config FUSBIDIO = OFF // USB USBID Selection (Controlled by Port Function) // DEVCFG2 7FF9B11A #pragma config FPLLIDIV = DIV_3 // System PLL Input Divider (3x Divider) #pragma config FPLLRNG = RANGE_5_10_MHZ // System PLL Input Range (5-10 MHz Input) #pragma config FPLLICLK = PLL_POSC // System PLL Input Clock Selection (POSC is input to the System PLL) #pragma config FPLLMULT = MUL_50 // System PLL Multiplier (PLL Multiply by 50) #pragma config FPLLODIV = DIV_2 // System PLL Output Clock Divider (2x Divider) #pragma config UPLLFSEL = FREQ_24MHZ // USB PLL Input Frequency Selection (USB PLL input is 24 MHz) #pragma config UPLLEN = OFF // USB PLL Enable (USB PLL is disabled) // DEVCFG1 7F7F3839 #pragma config FNOSC = SPLL // Oscillator Selection Bits (System PLL) #pragma config DMTINTV = WIN_127_128 // DMT Count Window Interval (Window/Interval value is 127/128 counter value) #pragma config FSOSCEN = OFF // Secondary Oscillator Enable (Disable SOSC) #pragma config IESO = OFF // Internal/External Switch Over (Disabled) #pragma config POSCMOD = EC // Primary Oscillator Configuration (External clock mode) #pragma config OSCIOFNC = ON // CLKO Output Signal Active on the OSCO Pin (Enabled) #pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disabled, FSCM Disabled) #pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576) #pragma config WDTSPGM = STOP // Watchdog Timer Stop During Flash Programming (WDT stops during Flash programming) #pragma config WINDIS = NORMAL // Watchdog Timer Window Mode (Watchdog Timer is in non-Window mode) #pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Disabled) #pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window size is 25%) #pragma config DMTCNT = DMT31 // Deadman Timer Count Selection (2^31 (2147483648)) #pragma config FDMTEN = OFF // Deadman Timer Enable (Deadman Timer is disabled) // DEVCFG0 FFFFFFF7 #pragma config DEBUG = OFF // Background Debugger Enable (Debugger is disabled) #pragma config JTAGEN = ON // JTAG Enable (JTAG Port Enabled) #pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2) #pragma config TRCEN = ON // Trace Enable (Trace features in the CPU are enabled) #pragma config BOOTISA = MIPS32 // Boot ISA Selection (Boot code and Exception code is MIPS32) #pragma config FECCCON = OFF_UNLOCKED // Dynamic Flash ECC Configuration (ECC and Dynamic ECC are disabled (ECCCON bits are writable)) #pragma config FSLEEP = OFF // Flash Sleep Mode (Flash is powered down when the device is in Sleep mode) #pragma config DBGPER = ALLOW_PG2 // Debug Mode CPU Access Permission (Allow CPU access to Permission Group 2 permission regions) #pragma config EJTAGBEN = NORMAL // EJTAG Boot (Normal EJTAG functionality) // DEVCP0 #pragma config CP = OFF // Code Protect (Protection Disabled) // SEQ0 // DEVADC1 // DEVADC2 // DEVADC3 // DEVADC4 // DEVADC5
Please remember a configuration bit can only be programmed logic 0, the unprogrammed state is logic 1, and device configuration bits may vary according to hardware and software. An important point is that PLL must output between 350 and 700 MHz. The PLL output is 400MHz in my configuration. Anyway, above configuration words work to me till now.
Configuration bits is set, then we will continue with main function. The main function is very simple, just toggle H0 to logic 1. But before we do that, we should change the direction of H0 to be output. For 8-bit PIC, we usually code that like below.
TRISHbits.TRISH0 = 0; // clear TRISH bit0, H0 to be output PORTHbits.RH0 = 1; // set PORTH bit0
But for PIC32, below code is recommended (use LATx to write IO, PORTx to read IO).
TRISHbits.TRISH0 = 0; LATHbits.LATH0 = 0;
Every PIC32 I/O module register has a corresponding CLR(clear), SET(set) and INV(invert) register designed to provide fast atomic bit manipulations, a value written to a SET, CLR or INV register effectively performs the implied operation, but only on the corresponding base register and only bits specified as '1' as modified. Bits specified as '0' are not modified.
So the above implemention has alternative option
TRISHCLR = (1<<0); // TRISH bit0 clear LATHSET = (1<<0); // LATH bit0 set '1'
It almost like
TRISH &= 0xFFFFFFFE; LATH |= 0x00000001;
But it performs faster and more effectively than above. So far, there is an important point not to clarify. The I/O port H0 mixes with analog feature, and the analog feature should be disabled. For this point, PIC32MZ is different than PIC32MX. On PIC32MX devices, the analog function of an I/O pin was determined by the PCFGx bit in AD1PCFG register. On PIC32MZ devices, the analog selection function has been moved into a separate register on each I/O port. Clear ANSxy (ANSELx<y>) bit to select digital mode.
Finally, the main code of "Hello world" is
#include <proc/p32mz2048ech144.h> #include "ConfigurationBits.h" //#define LED_IOCTL() TRISHbits.TRISH0 = 0 //#define LED_SETON() LATHbits.LATH0 = 1 //#define LED_OPEN() ANSELHbits.ANSH0 = 0 //#define LED_IOCTL() TRISH &= 0xFFFFFFFE //#define LED_SETON() LATH |= 0x00000001 //#define LED_OPEN() ANSELH &= 0xFFFFFFFE #define LED_IOCTL() TRISHCLR = (1<<0) #define LED_SETON() LATHSET = (1<<0) #define LED_OPEN() ANSELH &= 0xFFFFFFFE void main() { LED_OPEN(); LED_IOCTL(); LED_SETON(); while (1) { ; // do nothing } }
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本可避免的P1事故:Nginx变更导致网关请求均响应400
· 还在手写JSON调教大模型?.NET 9有新玩法
· 复杂业务系统线上问题排查过程
· 通过抓包,深入揭秘MCP协议底层通信
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· Coze Studio:字节跳动 Coze 的开源版本来了!第一时间深度解析
· 一款超级经典复古的 Windows 9x 主题风格 Avalonia UI 控件库,满满的回忆杀!
· 我给 AI 接上了一个 C# 运行器,结果它学会了自己上网、调试代码
· AI再强大,也不如人类员工用的爽?
· 我只说需求,AI 全程托管,代码自己长出来了!