这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo活动DigiKey第4期液体流量检测仪DIY(基础任务)

共2条 1/1 1 跳转至

Let'sdo活动DigiKey第4期液体流量检测仪DIY(基础任务)

高工
2025-01-20 17:22:54     打赏

使用STM32F103R在Keil环境中实现LED闪烁、OLED显示文字信息和继电器控制抽水泵通断的功能。


一、原理图:

板载LED引脚PA5,OLED使用IIC通信,使用的引脚是PB6,PB7,继电器控制使用的是PB12.

image.png

板载按键使用的是PC13.

image.png

二、连接示意图:

image.png

三、软件功能

MX配置:

按键,LED,IIC配置。

093bc7bd8ce7ab5f56998a4d9800bbb.png

IIC配置:

a3476efbe33aad3b4e05cc0a1d4baf4.png

定时器配置:

db0252e2886f2bd8561e87b718be33f.png

在STM32CubeMX中配置定时器(TIM),用于生成1秒的定时中断,配置GPIO引脚作为LED输出。


四、代码

GPIO初始化

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(RALEY_GPIO_Port, RALEY_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : KEY_Pin */
  GPIO_InitStruct.Pin = KEY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : LD2_Pin */
  GPIO_InitStruct.Pin = LD2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : RALEY_Pin */
  GPIO_InitStruct.Pin = RALEY_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(RALEY_GPIO_Port, &GPIO_InitStruct);

}

 中文文字库:

unsigned char F16x16[] =
{
0x10,0x60,0x02,0x8C,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,
0x04,0x04,0x7E,0x01,0x00,0xFE,0x88,0x48,0x48,0x00,0x7E,0x90,0x88,0x88,0xE4,0x00,/*"?",0*/

0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x40,0x80,0x00,
0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00,0x00,/*"?",1*/

0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0xE2,0x02,0x00,0x00,0x00,
0x00,0x00,0x7F,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x43,0x40,0x40,0x00,0x00,/*"?",2*/
	
0x00,0x00,0x7C,0x54,0x55,0x56,0x54,0x7C,0x54,0x56,0x55,0x54,0x7C,0x00,0x00,0x00,
0x01,0x01,0x01,0xFD,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0xFD,0x01,0x01,0x01,0x00,/*"?",3*/

0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0xF0,0x10,0x11,0x16,0xD0,0x10,0x10,0x00,
0x80,0x40,0x20,0x18,0x06,0x41,0x20,0x10,0x3F,0x44,0x42,0x41,0x40,0x40,0x78,0x00,/*"?",4*/

0x04,0x04,0x04,0x04,0xFF,0x24,0x24,0x24,0x24,0x24,0xFF,0x04,0x04,0x04,0x04,0x00,
0x44,0x44,0x24,0x24,0x15,0x0D,0x05,0xFF,0x05,0x0D,0x15,0x24,0x24,0x44,0x44,0x00,/*"?",5*/

0x04,0x04,0x04,0x04,0xFF,0x24,0x24,0x24,0x24,0x24,0xFF,0x04,0x04,0x04,0x04,0x00,
0x44,0x44,0x24,0x24,0x15,0x0D,0x05,0xFF,0x05,0x0D,0x15,0x24,0x24,0x44,0x44,0x00,/*"?",6*/
};


	unsigned char F16x161[] =
	{
// 电(0) 子(1) 产(2) 品(3) 世(4) 界(5) 第(6) 4(7)
// 期(8) 
//(9) L(10) e(11) t(12) '(13) s(14)  (15)
// d(16) o(17) '(18) D(19) i(20) g(21) i(22) K(23)
// e(24) y(25)  (26) 陪(27) 你(28) 渡(29) 过(30) 春(31)
// 夏(32) 秋(33) 冬(34) -(35) D(36) I(37) Y(38) 液(39)
// 体(40) 流(41) 量(42) 检(43) 测(44) 仪(45)

0xFF,0xFF,0x07,0x77,0x77,0x77,0x77,0x00,0x77,0x77,0x77,0x77,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xF7,0xF7,0xF7,0xF7,0x80,0x77,0x77,0x77,0x77,0x60,0x7F,0x0F,0xFF,/*"电",0*/
0x7F,0x7D,0x7D,0x7D,0x7D,0x7D,0x7D,0x1D,0x5D,0x6D,0x75,0x79,0x7D,0x7F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0x7F,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,/*"子",1*/
0xFF,0xFB,0x7B,0x7B,0x6B,0x1B,0x7A,0x79,0x7B,0x3B

中文函数:

// Parameters     : x,y -- ?????(x:0~127, y:0~7);
// Description    : ??ASCII_8x16.h????,16*16??
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x161[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x161[adder]);
		adder += 1;
	}
}
void OLED_ShowCN1(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x162[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x162[adder]);
		adder += 1;
	}
}


void OLED_ShowCN_STR(u8 x , u8 y , u8 begin , u8 num)
{
	u8 i;
	for(i=0;i<num;i++){OLED_ShowCN(i*16+x,y,i+begin);}    
}
void OLED_ShowCN_STR1(u8 x , u8 y , u8 begin , u8 num)
{
	u8 i;
	for(i=0;i<num;i++){OLED_ShowCN1(i*16+x,y,i+begin);}    
}

主函数功能:

HAL_TIM_Base_Start_IT(&htim2);

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		//HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
 // HAL_GPIO_WritePin(RALEY_GPIO_Port, RALEY_Pin, GPIO_PIN_SET);
		OLED_ShowStr(10,0,"WWW.EEPW.COM",2);			
		OLED_ShowCN_STR(10,3,0,6);							
		OLED_ShowCN_STR1(10,6,0,7);
//	OLED_DrawBMP(30,0,89,8,BMP1);						
		//OLED_DrawGIF(30,2,78,8,12,294,BMP2);			
	//	OLED_DrawGIF(30,2,78,8,12,294,bmp3);
		
		        if (read_key_state(KEY_GPIO_Port, KEY_Pin)) {
            // 切换继电器状态
            relayState = !relayState;
            HAL_GPIO_WritePin(RALEY_GPIO_Port, RALEY_Pin, relayState);
 
            // 等待一段时间以避免按键抖动影响
            HAL_Delay(DEBOUNCE_DELAY);
						}
  }
  /* USER CODE END 3 */
}

在中断服务程序中,切换LED状态,实现LED闪烁,用于生成1秒的定时中断。

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)   
{
    if (htim== &htim2)  
    {
	HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
    }
}



五、STM32定时器的理解与配置

基本功能介绍:

image.png

image.png

计算定时器的时间:

APB2的时钟为1分频故出来的APB2时钟还是72MHZ,TIM1对系统时钟APB2(72MHZ)再进行7200分频,然后计数重载初值设置为100,则一个定时周期Tout=(100-1+1)*(7200-1+1)/72,000,000=1/10=0.1s,即100ms为一个计数周期


六、实际效果

OLED显示效果

image.png

继电器工作指示:

image.png









专家
2025-01-20 21:23:30     打赏
2楼

感谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]