前言 : 无聊之余,突然想起来本人当初立志边学习边笔记的豪言壮语。手上正在操作恩智浦公司的LPC54114单片机,作这篇学习笔记让自己再次学习一下,也希望能给如当初的我那般四处搜寻资料学习的同学们一点帮助。水平有限,有不足之处望看官不吝指正!!谢谢。
一、编程环境
1、硬件环境
OM13089: LPCXpresso54114电路板 :搭载 以Arm? Cortex?M4为核心且带有256KB flash和192KB SRAM的LPC54114单片机
2、软件环境
(1)、Windows10 专业版 20H2 (2)、集成开发环境 Keil V5.31.0.0 (3)、代码参考 官方板级支持包 LPC5411X Xpresso54114 Keil Iar v3.00.001_35 (4)、Keil LPC54114软件包
PS: 相关芯片资料和开发板资料原理图等都可以去恩智浦官网找到。
二、创建点亮LED例程
说点题外话,不知道是否有习惯用STM32的同学,ST的STM32CubeMX工具在构建工程的时候确实有很多方便,而且其图形化的界面也挺直观的。这是有助于提高生产效率的, 但是对初学者来说个人并不推荐这种方法。个人观点,单片机编程入门除了要具有一定基本的C语言编程能力以外,对目标单片机架构了解也尤为重要。 个人接触过ST的STM32,STM8,NXP的LPC54xxx,LPC13xx,TI的MSP430,Atmel的Atmage64,以及入门的第一款单片机STC51单片机等等,不管是8位,16位,32位,还是ARM,AVR,C51,MSP,PIC。预定功能的实现,归根结底都是对芯片正确寄存器的填写。 现在像Keil5这样的IDE基本都有提供针对芯片的软件包支持,这些软件包都对特定芯片的模块功能进行了抽象,使用者不需要像使用C51那样直接操作寄存器,按照正确流程调用功能函数就行了,这对生产者来说无疑对提高生产效率卓有成效,但是对初学者来说,把示例代码复制过来,按照教程删删改改功能就实现了,目的如果是应付作业确实省事,却没啥意义。 以上并不是要教人怎么做事, 只是作者一点碎碎念,有捷径不用非要死磕那是SB,哈哈,进入正题。
1、硬件说明
官方开发板带有一颗RGBLED灯原理图LPCX5411x-Schematic.pdf如上图所示。本例使用Red灯来做演示。有兴趣的同学也可以用PWM做RGB调色,应该有点意思。
2、创建工程
1> 打开 Keil5 编程环境, 创建新工程命名为"BlueLed",选择目标设备"LPC54114J256BD64:M4"。 2>在manage run-time environment设置, 这里的用法是个人习惯, 读者可以自行选择。 3> 打开 Manage Project Items 根据自己习惯修改条目
4> 工程 C/C++ 设置
5> 新建 main.c 工程主体文件, 红标了主要的功能文件 6> 工程创建环节到此结束。 工程编译通过连接一下开发板。
3、参考官方例程完成编程
1> 打开 <lpc5411x_xpresso54114_keil_iar_v3.01.000\lpc5411x\prj_xpresso54114\keil\periph_blinky\periph_blinky.uvprojx>官方闪灯示例程序 2> main.c 完成代码如下
#include "chip.h"
#define RED_LED_PORT 0
#define RED_LED_PIN 29
#define TICKRATE_HZ 10
typedef enum
{
TURN_ON,
TURN_OFF,
} LED_STATES;
int main(void)
{
SystemCoreClockUpdate();
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_INPUTMUX);
SysTick_Config(SystemCoreClock / TICKRATE_HZ);
Chip_GPIO_Init(LPC_GPIO);
Chip_GPIO_SetPinDIROutput(LPC_GPIO, RED_LED_PORT, RED_LED_PIN);
Chip_GPIO_SetPinState(LPC_GPIO, RED_LED_PORT, RED_LED_PIN, TURN_ON);
while (1)
{
__WFI();
}
}
void SysTick_Handler(void)
{
Chip_GPIO_SetPinToggle(LPC_GPIO, RED_LED_PORT, RED_LED_PIN);
}
三、代码说明
1、keil_startup_lpc5411x.s
keil_startup_lpc5411x.s汇编语言源程序 是系统的启动文件。主要包括关于堆和栈的初始化配置(初学者对堆和栈的概念可能不清楚,请自行百度学习一下), 中断向量表的配置以及将程序引导到main()函数(调用 Reset Handler)
(1)、堆和栈的初始化
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000200
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000100
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
上述汇编代码可见,系统默认分配了512(0x200)字节栈空间用于程序运行时存放函数值和局部变量。默认分配256(0x100)字节的堆空间用于存放全局、静态变量,以及动态分配空间(Malloc()等函数)
(2)、中断向量表的配置
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemManage_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
__vector_table_0x1c
DCD 0 ; Checksum of the first 7 words
DCD 0
DCD 0 ; Enhanced image marker, set to 0x0 for legacy boot
DCD 0 ; Pointer to enhanced boot block, set to 0x0 for legacy boot
DCD SVC_Handler
DCD DebugMon_Handler
DCD 0
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD WDT_BOD_IRQHandler ; Watchdog Ored with BOD
DCD DMA_IRQHandler ; DMA Controller
DCD GINT0_IRQHandler ; GPIO Group0 Interrupt
DCD GINT1_IRQHandler ; GPIO Group1 Interrupt
DCD PIN_INT0_IRQHandler ; PIO INT0
DCD PIN_INT1_IRQHandler ; PIO INT1
DCD PIN_INT2_IRQHandler ; PIO INT2
DCD PIN_INT3_IRQHandler ; PIO INT3
DCD UTICK_IRQHandler ; UTICK timer
DCD MRT_IRQHandler ; Multi-Rate Timer
DCD CT32B0_IRQHandler ; CT32B0
DCD CT32B1_IRQHandler ; CT32B1
DCD SCT0_IRQHandler ; Smart Counter Timer
DCD CT32B3_IRQHandler ; CT32B3
DCD FLEXCOMM0_IRQHandler ; FLEXCOMM0
DCD FLEXCOMM1_IRQHandler ; FLEXCOMM1
DCD FLEXCOMM2_IRQHandler ; FLEXCOMM2
DCD FLEXCOMM3_IRQHandler ; FLEXCOMM3
DCD FLEXCOMM4_IRQHandler ; FLEXCOMM4
DCD FLEXCOMM5_IRQHandler ; FLEXCOMM5
DCD FLEXCOMM6_IRQHandler ; FLEXCOMM6
DCD FLEXCOMM7_IRQHandler ; FLEXCOMM7
DCD ADC_SEQA_IRQHandler ; ADC0 A sequence (A/D Converter) interrupt
DCD ADC_SEQB_IRQHandler ; ADC0 B sequence (A/D Converter) interrupt
DCD ADC_THCMP_IRQHandler ; ADC THCMP and OVERRUN ORed
DCD DMIC_IRQHandler ; Digital MIC
DCD HWVAD_IRQHandler ; Voice Activity detect
DCD USB_NEEDCLK_IRQHandler ; USB NeedCLK
DCD USB_IRQHandler ; USB
DCD RTC_IRQHandler ; RTC Timer
DCD IOH_IRQHandler ; Reserved
DCD MAILBOX_IRQHandler ; Mailbox
DCD PIN_INT4_IRQHandler ; PIO INT4
DCD PIN_INT5_IRQHandler ; PIO INT5
DCD PIN_INT6_IRQHandler ; PIO INT6
DCD PIN_INT7_IRQHandler ; PIO INT7
DCD CT32B2_IRQHandler ; CT32B2
DCD CT32B4_IRQHandler ; CT32B4
DCD Reserved_IRQHandler ; Reserved
DCD SPIFI_IRQHandler ; Reserved
单片机不可屏蔽中断和可屏蔽中断都在这了
(2)、进入主程序
normal_boot
LDR r0, =SystemInit
BLX r0
LDR r0, =__main
BX r0
ENDP
前面还有一系列关于芯片的操作有兴趣可以去相关汇编代码, 工程开始运行到这里进行系统的FPU初始化以及系统时钟配置(sysint.c)后进入用户主程序(main())
2、sysint.c
void SystemInit(void)
{
#if defined(__CODE_RED)
extern void(*const g_pfnVectors[]) (void);
SCB->VTOR = (uint32_t) &g_pfnVectors;
#else
extern void *__Vectors;
SCB->VTOR = (uint32_t) &__Vectors;
#endif
#if defined(CORE_M4)
#if defined(__FPU_PRESENT) && __FPU_PRESENT == 1
fpuInit();
#endif
#endif
#if !defined(__MULTICORE_M0SLAVE) && !defined(__MULTICORE_M4SLAVE)
#if defined(NO_BOARD_LIB)
Chip_SystemInit();
#else
Board_SystemInit();
#endif
#endif
}
设置向量表偏移量寄存器、使能fpu浮点运算单元、设置系统时钟。
3、main.c
使用SystemCoreClockUpdate()函数更新全局变量SystemCoreClock的值, 由于本例使用GPIO输出功能需要使能IOCON ,并使用Systic定时器提供闪烁定时服务。
红灯闪烁就到这里完成了
|