Keil 编程的常用代码示例
以下是针对 Keil 编程的常用代码示例,涵盖 8051 单片机和 STM32(Cortex-M3)的基础功能,包括 LED 控制、按键检测、定时器、中断、串口通信等,可直接在 Keil 中创建项目并使用。这些示例覆盖了嵌入式开发的核心基础功能,可作为扩展复杂项目的起点(如 PWM 控制、ADC 采样、I2C/SPI 通信等)。
·
文章目录
以下是针对 Keil 编程的常用代码示例,涵盖 8051 单片机和 STM32(Cortex-M3)的基础功能,包括 LED 控制、按键检测、定时器、中断、串口通信等,可直接在 Keil 中创建项目并使用。
一、8051 单片机代码示例
1. LED 闪烁(基础 IO 操作)
#include "reg51.h" // 8051 寄存器定义
// 定义 LED 引脚(假设接 P1.0)
sbit LED = P1^0;
// 简单延时函数(约 100ms,11.0592MHz 晶振)
void Delay100ms(void) {
unsigned int i, j;
for(i = 100; i > 0; i--)
for(j = 110; j > 0; j--);
}
void main(void) {
while(1) {
LED = 0; // 点亮 LED(低电平有效)
Delay100ms();
LED = 1; // 熄灭 LED
Delay100ms();
}
}
2. 按键控制 LED(按键检测与消抖)
#include "reg51.h"
sbit LED = P1^0; // LED 接 P1.0
sbit KEY = P3^2; // 按键接 P3.2(上拉输入,按下为低电平)
// 延时函数(用于按键消抖,约 10ms)
void Delay10ms(void) {
unsigned int i, j;
for(i = 10; i > 0; i--)
for(j = 110; j > 0; j--);
}
void main(void) {
LED = 1; // 初始熄灭
while(1) {
if(KEY == 0) { // 检测到按键按下
Delay10ms(); // 消抖
if(KEY == 0) { // 确认按下
LED = ~LED; // 翻转 LED 状态
// 等待按键释放
while(KEY == 0);
}
}
}
}
3. 定时器中断实现 LED 定时闪烁(定时器 0)
#include "reg51.h"
sbit LED = P1^0;
unsigned int cnt = 0; // 计数变量
// 定时器 0 初始化(1ms 中断一次,11.0592MHz 晶振)
void Timer0Init(void) {
TMOD |= 0x01; // 定时器 0 工作模式 1(16 位定时)
TH0 = 0xFC; // 初值装载(65536 - 1000 = 64536 = 0xFC18)
TL0 = 0x18;
ET0 = 1; // 使能定时器 0 中断
EA = 1; // 使能总中断
TR0 = 1; // 启动定时器 0
}
// 定时器 0 中断服务函数
void Timer0_ISR(void) interrupt 1 {
TH0 = 0xFC; // 重新装载初值
TL0 = 0x18;
cnt++;
if(cnt >= 1000) { // 累计 1000ms = 1s
cnt = 0;
LED = ~LED; // 翻转 LED 状态
}
}
void main(void) {
Timer0Init();
while(1); // 主循环空转,由中断处理逻辑
}
4. 串口通信(发送字符串,9600 波特率)
#include "reg51.h"
#include <string.h>
#define BAUD 9600 // 波特率
#define FOSC 11059200UL // 晶振频率
// 串口初始化
void UART_Init(void) {
SCON = 0x50; // 工作模式 1(8 位 UART,可变波特率)
// 计算定时器初值(模式 2 自动重装)
TMOD &= 0x0F; // 清除定时器 1 配置
TMOD |= 0x20; // 定时器 1 工作模式 2
TH1 = 256 - (FOSC / (12 * 32 * BAUD)); // 波特率公式
TL1 = TH1;
TR1 = 1; // 启动定时器 1
ES = 1; // 使能串口中断(可选,如需接收)
EA = 1; // 使能总中断
}
// 串口发送一个字符
void UART_SendChar(unsigned char c) {
SBUF = c; // 加载字符到发送缓冲区
while(TI == 0); // 等待发送完成
TI = 0; // 清除发送标志
}
// 串口发送字符串
void UART_SendString(unsigned char *str) {
while(*str != '\0') {
UART_SendChar(*str);
str++;
}
}
void main(void) {
UART_Init();
while(1) {
UART_SendString("Hello 8051!\r\n"); // 发送字符串
// 延时约 1s
unsigned int i, j;
for(i = 0; i < 1000; i++)
for(j = 0; j < 112; j++);
}
}
// 串口中断服务函数(如需接收数据)
void UART_ISR(void) interrupt 4 {
if(RI) { // 接收中断
RI = 0; // 清除接收标志
// 可在此处理接收的数据(SBUF 为接收值)
}
}
二、STM32(Cortex-M3,以 STM32F103 为例)代码示例
1. LED 闪烁(使用标准库)
#include "stm32f10x.h"
// 延时函数(简单循环,实际开发用定时器)
void DelayMs(uint32_t ms) {
uint32_t i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 7200; j++); // 约 1ms(72MHz 主频)
}
// LED 初始化(假设接 PA0)
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 PA 时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
int main(void) {
LED_Init();
while(1) {
GPIO_SetBits(GPIOA, GPIO_Pin_0); // 熄灭 LED(高电平有效)
DelayMs(500);
GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 点亮 LED
DelayMs(500);
}
}
2. 定时器中断(TIM2 定时 1s 翻转 LED)
#include "stm32f10x.h"
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 定时器 2 初始化(1ms 中断一次,72MHz 主频)
void TIM2_Init(void) {
TIM_TimeBaseInitTypeDef TIM_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能 TIM2 时钟
// 定时 1ms:72MHz / (7200 * 10) = 1000Hz → 周期 1ms
TIM_InitStruct.TIM_Prescaler = 7199; // 预分频器:7200-1
TIM_InitStruct.TIM_Period = 9; // 自动重装载值:10-1
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_InitStruct);
// 中断配置
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能更新中断
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2, ENABLE); // 启动定时器
}
// 定时器 2 中断服务函数
void TIM2_IRQHandler(void) {
static uint16_t cnt = 0;
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志
cnt++;
if(cnt >= 1000) { // 累计 1000ms = 1s
cnt = 0;
GPIO_WriteBit(GPIOA, GPIO_Pin_0,
(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0))); // 翻转 LED
}
}
}
int main(void) {
LED_Init();
TIM2_Init();
while(1);
}
3. 串口通信(USART1 发送/接收,115200 波特率)
#include "stm32f10x.h"
#include <stdio.h>
// 串口初始化(USART1,PA9 发送,PA10 接收)
void USART1_Init(uint32_t baudrate) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置 TX 引脚(PA9)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 RX 引脚(PA10)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 串口参数配置
USART_InitStruct.USART_BaudRate = baudrate;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 收发模式
USART_Init(USART1, &USART_InitStruct);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 接收非空中断
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
USART_Cmd(USART1, ENABLE); // 启动串口
}
// 串口发送一个字符
void USART1_SendChar(uint8_t c) {
USART_SendData(USART1, c);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完成
}
// 串口发送字符串
void USART1_SendString(uint8_t *str) {
while(*str) {
USART1_SendChar(*str++);
}
}
// 重定向 printf 到串口(需勾选 Use Micro LIB)
int fputc(int ch, FILE *f) {
USART1_SendChar((uint8_t)ch);
return ch;
}
// 串口 1 中断服务函数(接收数据并回传)
void USART1_IRQHandler(void) {
uint8_t data;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
data = USART_ReceiveData(USART1); // 读取接收数据
USART1_SendChar(data); // 回传数据( echo 功能)
}
}
int main(void) {
USART1_Init(115200); // 初始化串口,波特率 115200
while(1) {
printf("Hello STM32!\r\n"); // 发送字符串
// 延时约 1s
uint32_t i, j;
for(i = 0; i < 1000; i++)
for(j = 0; j < 7200; j++);
}
}
使用说明:
- 8051 示例:适用于 Keil C51 环境,需选择对应芯片(如 AT89C51),注意晶振频率对延时和波特率的影响。
- STM32 示例:适用于 Keil MDK-ARM 环境,需安装 STM32F1 固件库,项目中需添加启动文件(如
startup_stm32f10x_md.s)和系统文件(如system_stm32f10x.c)。 - 调试建议:先通过软件仿真验证逻辑,再连接硬件调试;注意引脚定义需与实际电路匹配。
这些示例覆盖了嵌入式开发的核心基础功能,可作为扩展复杂项目的起点(如 PWM 控制、ADC 采样、I2C/SPI 通信等)。
更多推荐
所有评论(0)