沁恒CH32V307舵机及LCD显示屏的驱动————SayOhYeah
简介
舵机期待从信号线收到一个周期约为20ms(即50Hz)的PWM脉冲。脉冲的高电平持续时间决定了舵机的角度。
- 高电平持续 0.5ms → 舵机转到 0度(最左端)
- 高电平持续 1.5ms → 舵机转到 90度(中间位置)
- 高电平持续 2.5ms → 舵机转到 180度(最右端)
单片机(如Arduino、STM32、51单片机)的工作就是精确地产生这些不同宽度的脉冲
舵机开发流程
定义舵机的PWM周期和占空比
#define PWM_PERIOD 20000 // PWM周期为20ms (20000us)
#define PWM_MIN 500 // 最小脉宽为0.5ms (500us)
#define PWM_MAX 2500 // 最大脉宽为2.5ms (2500us)
初始化定时器生成PWM信号
使能定时器时钟
-
配置定时器基本参数
-
配置该定时器的PWM模式
-
配置定时器的通道
void TIM2_PWM_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2时钟 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 配置TIM2的基本参数 TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; // 设置自动重装值 TIM_TimeBaseStructure.TIM_Prescaler = 96 - 1; // 设置预分频器,96MHz/96 = 1MHz (1us) TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 配置TIM2的PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_MIN; // 初始占空比为最小值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 配置TIM2通道1 TIM_OC1Init(TIM2, &TIM_OCInitStructure); // 使用TIM2的通道1 TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能TIM2通道1的预装载寄存器 TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能TIM2的自动重装寄存器预装载 TIM_Cmd(TIM2, ENABLE); // 使能TIM2 }初始化GPIO输出PWM信号
- 使能GPIO的时钟
- 配置io口的模式
void GPIO_Init_PWM(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟 GPIO_InitTypeDef GPIO_InitStructure; // 配置PA0为复用推挽输出(TIM2通道1) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); }
LCD屏幕显示
LCD电路与CH32V307的引脚分配如下表所示:
| MCU引脚 | LCD电路 | 备注 |
|---|---|---|
| PB3 | SCL | SPI时钟 |
| PB5 | SDA | 主输出从输入 |
| NRST | RES | 复位 |
| PD3 | DC | 命令/数据 |
| PD4 | CS | 片选线 |
- 文字脱模配置:C51格式
LCD开发流程
初始化LCD
void SPI_LCD_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3,ENABLE);
//CS DC BL端口初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_SetBits(GPIOD, GPIO_Pin_3); //DC
GPIO_SetBits(GPIOD, GPIO_Pin_4); //CS
GPIO_SetBits(GPIOD, GPIO_Pin_5); //BL
//spi端口初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_15);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOB, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitStructure );
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI3, &SPI_InitStructure);
SPI_Cmd(SPI3, ENABLE);
}
课后作业
开机(显示开机过程,文字提示,进度条)-------开机成功(文字提示,相应底色背景图)------舵机动一下(显示门已经上锁等待五秒后舵机动90度显示门已开启)
#include "debug.h"
#include "lcd.h"
#include "clock.h"
#include "pic.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
TIM2_PWM_Init();
GPIO_Init_PWM();
TIM_SetCompare1(TIM2,1500);
LCD_Init();//LCD初始化
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
LCD_ShowPicture(65,80,40,40,gImage_1);
LCD_ShowChinese(30,50,"正",RED,WHITE,16,0);
LCD_ShowChinese(30+16,50,"在",RED,WHITE,16,0);
LCD_ShowChinese(30+32,50,"启",RED,WHITE,16,0);
LCD_ShowChinese(30+48,50,"动",RED,WHITE,16,0);
uint8_t i = 0;
while(i < 128) {
LCD_DrawLine(i,125,i,125,BLUE);
i++; // 明确地自增
Delay_Ms(50);
}
LCD_ShowPicture(1,1,128,128,gImage_2);
LCD_ShowChinese(30,100,"启",RED,WHITE,16,0);
LCD_ShowChinese(30+16,100,"动",RED,WHITE,16,0);
LCD_ShowChinese(30+32,100,"成",RED,WHITE,16,0);
LCD_ShowChinese(30+48,100,"功",RED,WHITE,16,0);
Delay_Ms(5000);
LCD_ShowPicture(1,1,128,128,gImage_2);
LCD_ShowChinese(30,30,"门",RED,WHITE,16,0);
LCD_ShowChinese(30+16,30,"已",RED,WHITE,16,0);
LCD_ShowChinese(30+32,30,"上",RED,WHITE,16,0);
LCD_ShowChinese(30+48,30,"锁",RED,WHITE,16,0);
clock(1);
Delay_Ms(5000);
clock(0);
LCD_ShowChinese(30,30,"门",RED,WHITE,16,0);
LCD_ShowChinese(30+16,30,"已",RED,WHITE,16,0);
LCD_ShowChinese(30+32,30,"开",RED,WHITE,16,0);
LCD_ShowChinese(30+48,30,"启",RED,WHITE,16,0);
while(1)
{
}
}