A FreeRTOS-based countdown timer for PIC24 microcontrollers. It supports time entry over UART, LED feedback, potentiometer-controlled brightness, and pause/resume control.
The system runs a simple state machine that controls a countdown timer. Time is entered through a UART terminal, buttons control the flow, and LEDs provide visual feedback. FreeRTOS handles tasks, timing, and concurrency.
Target: PIC24 (dsPIC33/PIC24 family)
RTOS: FreeRTOS
- PIC24 or dsPIC33
- 16 MHz input (configured to 96 MHz PLL)
Push Buttons:
- PB1: Enter time mode
- PB2: Used with PB3 to start
- PB3: Pause, resume, abort
LEDs:
- LED0 (RB5): Completion
- LED1 (RB6): Countdown blink
- LED2 (RB7): PWM brightness
Other:
- Potentiometer: AN5 (RA3)
- UART2: For all terminal IO
All pin definitions are in hw_config.h:
- LED0: RB5
- LED1: RB6
- LED2: RB7
- ADC: AN5 (RA3)
- State-based operation
- UART time entry in MM:SS
- One-second accurate countdown
- LED animations for every state
- Software PWM for LED2
- ADC brightness control
- Pause/resume
- Abort via long press
- Optional info display (ADC + duty cycle)
- LED2 mode toggle (solid or blink)
- Backspace support
- LED2 pulses
- PB1 starts time entry
- Terminal shows a welcome message
- User enters MM:SS over UART
- Input is echoed
- Validates minutes and seconds
- Enter stores time
- PB2+PB3 long press clears input
- LEDs off
- PB2+PB3 click starts the countdown
- PB2+PB3 long press clears the stored time
- LED1 blinks
- LED2 brightness controlled by ADC
- PB3 click pauses
- PB3 long press aborts
- 'i' toggles extended info
- 'b' toggles LED2 mode
- Terminal overwrites the same line with remaining time
- LEDs freeze
- ADC still updates LED2 brightness
- Same controls as COUNTDOWN
- LED0 and LED1 alternate for 5 seconds
- LED2 stays solid
- Shows completion message
- Auto-returns to WAITING
- MPLAB X
- XC16
- FreeRTOS source
make clean
make build- Open project
- Select default config
- Build (F11)
- Debug:
dist/default/debug/*.elf - Production:
dist/default/production/*.hex
- Flash the hex file
- Open UART2 at 115200 baud
- Power the board
- Ensure system is in WAITING (LED2 pulsing)
- PB1 enters time input
- Enter MM:SS
- Press Enter
- PB2+PB3 starts the countdown
- Pause: PB3 click
- Resume: PB3 click
- Abort: PB3 long press
- Change brightness: turn potentiometer
- Toggle info: press 'i'
- Toggle LED2 mode: press 'b'
- LEDs go into the finish pattern
- System resets after 5 seconds
| Key | Function |
|---|---|
| MM:SS | Enter time |
| Enter | Submit |
| Backspace | Remove last char |
| i | Show/hide ADC + duty cycle |
| b | Toggle LED2 mode |
| Action | Buttons | Function |
|---|---|---|
| Enter time | PB1 | Start input |
| Start countdown | PB2 + PB3 | Begin countdown |
| Clear time | PB2 + PB3 (hold) | Reset input |
| Pause/Resume | PB3 | Toggle pause |
| Abort | PB3 (hold) | Stop immediately |
freertos-start.X 2/
├── main.c
├── app.h
├── hw_config.h
├── FreeRTOSConfig.h
│
├── adc.c / adc.h
├── buttons.c / buttons.h
├── pwm.c / pwm.h
├── uart.c / uart.h
│
├── FreeRTOS/
│ ├── include/
│ ├── portable/
│ └── *.c
│
├── build/
├── dist/
└── nbproject/
main.c: Tasks and state machineapp.h: Global definitions, RTOS objectshw_config.h: Pin definitions and hardware macrosadc.c: AN5 sampling and conversionpwm.c: Software PWMbuttons.c: Debouncing, click/long-press detection
- Max priority: 3
- Tick rate: 1 kHz
- Static allocation (heap_1)
- PIC24/dsPIC33 port
- 3: PWM
- 2: Countdown, Buttons
- 1: Time input, Waiting
- 0: ADC, Idle
- Countdown resolution: 1 s
- LED1 blink: 1 Hz
- LED2 PWM: defined in pwm.c
- Debounce: ~50 ms
- Long press: >1 s
- Finish sequence: 5 s
- 10-bit
- AN5
- Manual sample/convert
- ~20 microsecond conversion time
- Software-driven
- Duty cycle mapped from ADC
- Used for pulsing and brightness
- Queues: Button events, UART RX
- Semaphores: start signals
- Mutexes: UART printing, state, countdown value
- All tasks have fixed stack sizes
- No dynamic allocation during runtime
- Time not validated
- PB2+PB3 not pressed together
- Not in READY state
- Check ADC wiring
- Check AN5 config
- Press 'i' to verify ADC values
- Confirm 115200 baud
- Check TX/RX pins
- Terminal must send CR+LF
- Check debounce logic
- Verify pin setup
- Ensure button task is active