智能门锁第二讲

沁恒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)
    {


    }

}