嵌入式系统应用-第十二章 综合应用

第十二章 综合应用

本章模块的最后介绍,通过6小实验来结束本次课程的介绍。

12.1 led灯操作

12.1.1 背景介绍

触摸屏控制led1灯亮和灯灭

12.1.1 初始化led灯

首先初始硬件,调用硬件初始化函数

LED_Init(RT_NULL)

12.1.2 插入驱动函数

在图形库的回调函数里面,插入执行的动作

void Event_BtnLED(lv_event_t *e)   // 打开led灯
{
   LED_Status sta;
	sta=led_on;
	LED_Ctr(RT_NULL,led1,&sta);
	
}

void Event_BtnLED1(lv_event_t *e)  // 关闭led灯
{
    LED_Status sta;
	sta=led_off;
	LED_Ctr(RT_NULL,led1,&sta);
	
}

12.1.3 演示效果

观看视频,可以查看演示效果

led灯操作

12.2 工作指示灯操作

12.2.1 背景介绍

创建一个线程来控制灯每隔500ms闪烁

12.2.2 线程创建

首先再用静态函数,创建一个线程。

rt_thread_init(&led_blink_thread,"led_blnk",led_blink_thread_entry,RT_NULL,&led_blink_thread_stack[0],	sizeof(led_blink_thread_stack),THREAD_PRIORITY+1 , THREAD_TIMESLICE);	
rt_thread_startup(&led_blink_thread);

12.2.3 线程入口函数

创建线程的入口函数,并且说明函数的动作


ALIGN(RT_ALIGN_SIZE)
static char led_blink_thread_stack[128];
static struct rt_thread led_blink_thread;

/* ? ? ??? ? ? */
static void led_blink_thread_entry(void *param)
{			
	 while(1)  // ?????
	 {
			LED_Status sta;
			sta=led_on;
			LED_Ctr(RT_NULL,led0,&sta);
				rt_thread_mdelay(500);
			sta=led_off;		 
			LED_Ctr(RT_NULL,led0,&sta);
				rt_thread_mdelay(500);
		  
		}
}

12.2.4 演示效果

led灯操作

12.3 蜂鸣器操作

12.3.1 背景介绍

触摸屏控制蜂鸣器 响和灭

12.3.2 初始化蜂鸣器

硬件初始化

	BEEP_Init();

12.3.4 控制蜂鸣器响

插入按键效果

void Event_BtnSpeaker(lv_event_t *e)   // 蜂鸣器响
{
 //   lv_obj_set_style_bg_color(mainTitle, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
	  BEEP_Ctr(beep_on);
}

void Event_BtnSpeaker1(lv_event_t *e)  // 蜂鸣器灭
{
//    lv_obj_set_style_bg_color(mainTitle, lv_palette_main(LV_PALETTE_BLUE), LV_PART_MAIN);
	  BEEP_Ctr(beep_off);
}

12.4 屏幕亮度调节操作

12.4.1 背景介绍

屏幕调节屏幕亮度

12.4.2 初始化亮度

已经在屏幕显示完成驱动

12.4.3 调节亮度

插入动作效果,获取滑动条的数值,输入给灯光控制

void slider_event_cb(lv_event_t* e)   // 控制屏幕亮度
{
    lv_obj_t* slider = lv_event_get_target(e);
	  int a =(int)lv_slider_get_value(slider);
    char buf[8];
    lv_snprintf(buf, sizeof(buf), "%d%%", a);
    lv_label_set_text(slider_label, buf);
    // 写入亮度
	  LCD_Set_BL(a);
}

12.4.3 显示效果

蜂鸣器的操作

12.5 光线强度操作

12.5.1 背景介绍

光线强度,调节状态条的值

12.5.2 初始化硬件

15.5.2.1 电路图分析

嵌入式系统应用-第十二章 综合应用_第1张图片
对应IO口:PF7口

在这里插入图片描述
ADC 采样: 用ADC3模块的通道5

在这里插入图片描述
DMA2的通道和数据流:可以选择通道2,数据流0或者数据流1
嵌入式系统应用-第十二章 综合应用_第2张图片

12.5.2.2 驱动代码

配置好头文件

#ifndef __ADC_H
#define __ADC_H


#include "stm32f4xx.h"

#define ADCx_CLK RCC_APB2Periph_ADC3

#define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOF

#define GPIO_PIN  GPIO_Pin_7

#define GPIO_PORT GPIOF

#define DMA_CHANNELx  DMA_Channel_2

#define ADCx_DR_ADDRESS   (&ADC3->DR)

#define  DMA_STREAMx DMA2_Stream1

#define ADCx ADC3

#define ADC_CHANNEL ADC_Channel_5

void ADC_Config(void);

extern __IO uint16_t uhADCxConvertedValue;

#endif


初始化ADC和DMA 的模组


__IO uint16_t uhADCxConvertedValue = 0;
__IO uint32_t uwADCxConvertedVoltage = 0;

static void ADC_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;

  /* Enable ADCx, DMA and GPIO clocks ****************************************/ 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE);  
  RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
  

  /* DMA2 Stream0 channel2 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_CHANNELx;  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADCxConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA_STREAMx, &DMA_InitStructure);
  DMA_Cmd(DMA_STREAMx, ENABLE);

  /* Configure ADC3 Channel7 pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIO_PORT, &GPIO_InitStructure);

  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC3 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADCx, &ADC_InitStructure);

  /* ADC3 regular channel7 configuration **************************************/
  ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_3Cycles);

 /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);

  /* Enable ADC3 DMA */
  ADC_DMACmd(ADCx, ENABLE);

  /* Enable ADC3 */
  ADC_Cmd(ADCx, ENABLE);
}

启动adc 转化

  /* Start ADC Software Conversion */ 
  ADC_SoftwareStartConv(ADCx);

12.5.3 创建一个线程获取光线强度和设定状态条的值

		err=rt_thread_init(&light_thread,"light",light_thread_entry,RT_NULL,&light_thread_stack[0],
		sizeof(light_thread_stack),6, THREAD_TIMESLICE);
		err=rt_thread_startup(&light_thread);
		if(err!=RT_EOK)
		{
			rt_kprintf("light_thread fail\r\n");
			while(1);
		}

创建入口函数


ALIGN(RT_ALIGN_SIZE)
static char light_thread_stack[512];
struct rt_thread light_thread;

/* ? ? ??? ? ? */
static void light_thread_entry(void *param)
{			
	
	 while(1)  // ?????
	 {				   
		  rt_mutex_take(&lvgl_mutex,RT_WAITING_FOREVER);
    
  		  Light_Bar_Set_Value( uhADCxConvertedValue/17);			
			
		  rt_mutex_release(&lvgl_mutex);

			rt_thread_mdelay(1000);
		  
		}
}

12.5.4 演示效果

AD 采样

12.6 万年历操作

12.6.1 背景介绍

在彩色屏幕上面显示 年、月 和日

12.6.2 RTC 介绍

RTC 由两个主要部分组成(如图 3.1 所示)。第一部分(APB1 接口)用来和 APB1 总线
相连。此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作 APB1 接口
由 APB1 总线时钟驱动,用来与 APB1 总线接口。 另一部分(RTC 核心)由一组可编程计
数器组成,分成两个主要模块。第一个模块是 RTC 的预分频模块,它可编程产生最长
为 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程分频器
(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周
期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程计数器,可被初始
化为当前的系统时间。系统时间按 TR_CLK 周期累加并与存储在 RTC_ALR 寄存器中的可
编程时间相比较,如果 RTC_CR 控制寄存器中设置了相应允许位,比较匹配时将产生一
个闹钟中断。

嵌入式系统应用-第十二章 综合应用_第3张图片

12.6.3 硬件初始化

#include "rtc.h"
#include 

#define RTC_CLOCK_SOURCE_LSI
//uint8_t aShowTime[50] = {0};
	
__IO uint32_t uwAsynchPrediv = 0;
__IO uint32_t uwSynchPrediv = 0;

RTC_TimeTypeDef  RTC_TimeStructure;
RTC_InitTypeDef  RTC_InitStructure;
RTC_AlarmTypeDef RTC_AlarmStructure;

void RTC_Config(void)
{
  RTC_DateTypeDef RTC_DateStructure;
  
  /* Enable the PWR clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

  /* Allow access to RTC */
  PWR_BackupAccessCmd(ENABLE);
    
#if defined (RTC_CLOCK_SOURCE_LSI)  /* LSI used as RTC source clock*/
  /* The RTC Clock may varies due to LSI frequency dispersion */   
  /* Enable the LSI OSC */ 
  RCC_LSICmd(ENABLE);

  /* Wait till LSI is ready */  
  while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {
  }

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  
  /* ck_spre(1Hz) = RTCCLK(LSI) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
  uwSynchPrediv = 0xFF;
  uwAsynchPrediv = 0x7F;

#elif defined (RTC_CLOCK_SOURCE_LSE) /* LSE used as RTC source clock */
  /* Enable the LSE OSC */
  RCC_LSEConfig(RCC_LSE_ON);

  /* Wait till LSE is ready */  
  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {
  }

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  /* ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
  uwSynchPrediv = 0xFF;
  uwAsynchPrediv = 0x7F;

#else
  #error Please select the RTC Clock source inside the main.c file
#endif /* RTC_CLOCK_SOURCE_LSI */
  
  /* Enable the RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC APB registers synchronisation */
  RTC_WaitForSynchro();
  
  /* Configure the RTC data register and RTC prescaler */
  RTC_InitStructure.RTC_AsynchPrediv = uwAsynchPrediv;
  RTC_InitStructure.RTC_SynchPrediv = uwSynchPrediv;
  RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
  RTC_Init(&RTC_InitStructure);
  
  /* Set the alarm 05h:20min:30s */
  RTC_AlarmStructure.RTC_AlarmTime.RTC_H12     = RTC_H12_AM;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours   = 0x05;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = 0x20;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = 0x30;
  RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31;
  RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
  RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;
  
  /* Configure the RTC Alarm A register */
  RTC_SetAlarm(RTC_Format_BCD, RTC_Alarm_A, &RTC_AlarmStructure);
  
  /* Enable RTC Alarm A Interrupt */
  RTC_ITConfig(RTC_IT_ALRA, ENABLE);
  
  /* Enable the alarm */
  RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
  
  RTC_ClearFlag(RTC_FLAG_ALRAF);
  
  /* Set the date: Friday January 11th 2013 */
  RTC_DateStructure.RTC_Year = 0x13;
  RTC_DateStructure.RTC_Month = RTC_Month_January;
  RTC_DateStructure.RTC_Date = 0x11;
  RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Saturday;
  RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);
  
  /* Set the time to 05h 20mn 00s AM */
  RTC_TimeStructure.RTC_H12     = RTC_H12_AM;
  RTC_TimeStructure.RTC_Hours   = 0x05;
  RTC_TimeStructure.RTC_Minutes = 0x20;
  RTC_TimeStructure.RTC_Seconds = 0x00; 
  
  RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);   
  
  /* Indicator for the RTC configuration */
  RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}

12.6.4 创建一个线程,获取年月日、时分秒。

这里获取秒线程会比较高,获取年月日的时间比较慢

ALIGN(RT_ALIGN_SIZE)
static char cal_thread_stack[512];
struct rt_thread cal_thread;

/* ? ? ??? ? ? */
static void cal_thread_entry(void *param)
{			
	 u32 cnt=0;
	 while(1)  // ?????
	 {				   
		  rt_mutex_take(&lvgl_mutex,RT_WAITING_FOREVER);
    
			RTC_TimeShow();
		 
		  if(cnt>20)
			{
				RTC_DateShow();
			    cnt=0;	
			}
			else
				 cnt++;
			
		  rt_mutex_release(&lvgl_mutex);

			rt_thread_mdelay(500);
		 
		 
		  
		}
}

static void Start_Thread(void)
{

		rt_thread_init(&cal_thread,"light",light_thread_entry,RT_NULL,&cal_thread_stack[0],
		sizeof(cal_thread_stack),6, 5);
		rt_thread_startup(&cal_thread);
	

}


static void Delete_Thread(void)
{
		rt_thread_detach(&cal_thread);
}

12.6.5 显示年、月、日 和时、分 和秒


static RTC_TimeTypeDef  RTC_TimeStructure;
static RTC_DateTypeDef RTC_DateStructure;
uint8_t aShowTime[50] = {0};
/
**
  * @brief  Display the current time.
  * @param  None
  * @retval None
  */
void RTC_TimeShow(void)
{
  /* Get the current Time */
  RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
  /* Display time Format : hh:mm:ss */
  sprintf((char*)aShowTime,"%0.2d:%0.2d:%0.2d",RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, RTC_TimeStructure.RTC_Seconds);
  lv_label_set_text(label_day, (char*)aShowTime);  // 更新值
	
	
}

// 获取年月日
void RTC_DateShow(void)
{

 /* Get the current Time */
  RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
  /* Display time Format : hh:mm:ss */
  sprintf((char*)aShowTime,"%0.2d:%0.2d:%0.2d",RTC_DateStructure.RTC_Year, RTC_DateStructure.RTC_Month, RTC_DateStructure.RTC_Date);
  lv_label_set_text(label_date, (char*)aShowTime); // 更新值
	

}

12.6.6 创建线程和删除线程

由于线程不会一直运行,只有等这个应用工作的时候,才会运行这个结果。

static void Delete_MainWindow(lv_obj_t* mainScreen)
{
    if (label_date!= NULL)
        lv_obj_del(label_date);

    if (btn_return != NULL)
        lv_obj_del(btn_return);

    if (label_day != NULL)   // 删除数据
        lv_obj_del(label_day);
		
		Delete_Thread();    // 删除线程
}


// 返回按键
static void Event_BtnReturn(lv_event_t *e)
{
    lv_obj_t* mainScreen = lv_scr_act();
    switch (winPoint)  // 绘制不同界面
    {
    case main_desktop:   break;             // 错误界面
    case ligh_strengh:   break;
    case rtc:   Delete_MainWindow(mainScreen); Draw_MainFrame();winPoint = main_desktop;   break;
    }
}

void RTCFrame(void)
{
    lv_obj_t* mainScreen = lv_scr_act();
    Create_MainWindow(mainScreen);
	Start_Thread();   // 创建线程
}

12.6.7 显示结果

rtc

12.7 总结

通过几个小实验,对前面的知识点进行总结。 掌握线程创建、图形库的使用和片上资源的合理配置。

你可能感兴趣的:(stm32,嵌入式硬件)