Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 手機背夾設計

手機背夾設計

編輯:關於Android編程

一、整體概念設計

為手機設計的一種背夾,具有OTG功能、hub和充電功能功能。具體如下:

1、只插入手機時,手機處於host狀態,充電寶給手機充電,同時手機可以訪問充電寶上的SD卡

2、插入電腦後,電腦處於host狀態,手機和sd都是slave狀態

3、充電寶上有4個led,顯示電量

4、手機通過PD與充電寶進行通信與交互

 

硬件芯片:STM32F030C8T6

開發環境:windows xp/win7

開發工具:IAR+STM32CUBEMX+ST_LINKER

二、各個模塊設計

主要包括了充電、放電、主從切換以及PD通信等主要的4個模塊。下面從每個模塊說起

1、充電模塊

這裡充電采用的IC是BQ25895,帶BC1.2協議的芯片,充電部分主要模仿MTK平台上的switch charging,具體driver code 如下:

 

#include "stm32f0xx_hal.h"
#include "switch_charging.h"

extern int8_t UI_Percentage;
uint8_t charging_state=CHR_PRE;
extern uint8_t charger_type;
int16_t temp_input_cc_value;
int16_t temp_cc_value;


static void select_charging_current()
{
	switch (charger_type)
	{
		case STANDARD_HOST: //sdp usb host for max 500ma
			temp_input_cc_value=500;
			temp_cc_value=500;
			break;
		case CHARGING_HOST: //cdp for max 1.5a
			temp_input_cc_value=1500;
			temp_cc_value=1500;
			break;
		case STANDARD_CHARGER: //dcp for max3.25a
			temp_input_cc_value=3000;
			temp_cc_value=3000;
			break;
		case UNKNOWN_CHARGER: //500ma
			temp_input_cc_value=500;
			temp_cc_value=500;
			break;
		case NON_STANDARD_CHARGER: //appale charger 1a
			temp_input_cc_value=1000;
			temp_cc_value=1000;
			break;
		case NO_CHARGER:
			break;
	}
}

void pchr_turn_on_charging()
{
	/***1:gpio enable***/
	HAL_GPIO_WritePin(GPIOA, GPIO_CHG_EN_Pin, GPIO_PIN_RESET);
	/***gpio enable***/
	
	/***2:bq24595 reg init for charging***/
	/***bq24595 reg init for charging***/	

	/***3:select charging current***/
	select_charging_current();
	bq2589x_set_input_current_limit(temp_input_cc_value);
	bq2589x_set_chargecurrent(temp_cc_value);
	/***select charging current***/	

	/***4:set cc_cv voltage***/
	/***set cc_cv voltage***/
	
	/***5:enable charging***/
	bq2589x_enable_charge();
	/****enable charging***/
	
}

static uint8_t charging_full_check()
{
	uint8_t state;
	state=bq2589x_is_charge_done();
	return state;
}

void Pre_Charge_Mode()
{
	pchr_turn_on_charging();
	if(UI_Percentage==100)
		charging_state=CHR_FULL;
	else charging_state=CHR_CC;
}

void Constant_Charge_Mode()
{
	pchr_turn_on_charging();
	if(charging_full_check()==TRUE)
		charging_state=CHR_FULL;
}

void Battery_Full()
{
	if(charging_full_check()==FALSE)
		charging_state=CHR_CC;
	
}
void mt_battery_charging_algorithm(void)//just like the mtk switch charging.
{
	switch (charging_state)
	{
		case CHR_PRE:
			Pre_Charge_Mode();
			break;
		case CHR_CC:
			Constant_Charge_Mode();
			break;
		case CHR_FULL:
			Battery_Full();
			break;
		default:
			break;
	}
}
 

 

2、放電模塊

 

放電模塊模仿的是展訊平台的,由於系統不帶有硬件庫侖計,只能采用通過讀取電池的電壓來換算成電池電量。 這裡需要注意以下幾點:

(1)、電池電量的變化不能出現跳變,充電時逐漸+1,放電時逐漸-1,

(2)、充電時電量只能增加,放電時只能減少

 

#include "stm32f0xx_hal.h"
#include "battery_common.h"

int8_t UI_Percentage;
uint8_t chr_det=FALSE;
uint8_t charger_type;
uint8_t usb_typec_plug_in;
uint8_t battery_run_timer=FALSE;

uint8_t phone_is_online = FALSE;
uint8_t pc_is_online =FALSE;
uint8_t charger_is_online = FALSE;

extern uint8_t charging_state;
extern uint8_t sleep_mode;
uint8_t need_init;


/* usb mode select */
void Usb_Sel_Host(enum host_is host_type)
{
    if(host_type==PC)
	{
		HAL_GPIO_WritePin(GPIOA, USB_SEL_Pin, GPIO_PIN_SET);

	}
	else if(host_type==PHONE)
	{
		HAL_GPIO_WritePin(GPIOA, USB_SEL_Pin, GPIO_PIN_RESET);
	}
	else if(host_type==NONE)
	{
		
	}
}
void check_host_is()
{
	if(pc_is_online==TRUE && phone_is_online==TRUE)
	{
		Usb_Sel_Host(PC);
	}
	else if(pc_is_online==TRUE && phone_is_online==FALSE)
	{
		Usb_Sel_Host(PC);
	}
	else if(pc_is_online==FALSE && phone_is_online==TRUE)
	{
		Usb_Sel_Host(PHONE);
	}
	else if(pc_is_online==FALSE && phone_is_online==FALSE)
	{
		Usb_Sel_Host(NONE);
	}
}
/* interrupt for EINT_CHR_STAT callback */
void check_chrdet_type()
{
	uint8_t temp_charger_type;
	
	temp_charger_type=bq2589x_read_vbus_type();
	
	if(temp_charger_type==0)
		charger_type=NO_CHARGER;
	else if(temp_charger_type==1)
		charger_type=STANDARD_HOST;
	else if(temp_charger_type==2)
		charger_type=CHARGING_HOST;
	else if(temp_charger_type==3)
		charger_type=STANDARD_CHARGER;
	else if(temp_charger_type==5)
		charger_type=UNKNOWN_CHARGER;
	else if(temp_charger_type==6)
		charger_type=NON_STANDARD_CHARGER;
	
	if(temp_charger_type!=0 || temp_charger_type!=7)//0:no charger,7:OTG
	{
		charger_is_online= TRUE;
		chr_det = TRUE;
	}
	else{
		charger_is_online= FALSE;
		chr_det = FALSE;
	}
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin==EINT_CHG_STAT_Pin)
	{
		check_chrdet_type();
		if(charger_type==STANDARD_HOST || charger_type==CHARGING_HOST)
			pc_is_online = TRUE;
		else
			pc_is_online = FALSE;
	}
	else if(GPIO_Pin==CC_INT_Pin)
	{
		if(usb_typec_plug_in==TRUE)
		{
			phone_is_online = TRUE;
		}else if(usb_typec_plug_in==FALSE)
		{
			phone_is_online = FALSE;
		}
	}
	else if(GPIO_Pin==POWER_ON_N_Pin)
	{
		if(sleep_mode==0)
			enter_stopmode();
	}
	check_host_is();
	if(sleep_mode==1)
	{
		need_init=1;
		sleep_mode =0;
	}
}

static void sync_UI_percentage()
{
	uint8_t percentage_temp;
	uint8_t timer=0;
	
	percentage_temp = get_battery_percentage();

	if(chr_det==TRUE)
	{
		if(UI_Percentage100)
			UI_Percentage=100;		
	}else if(chr_det==FALSE)
	{
		if(UI_Percentage>percentage_temp)
			timer++;
		else timer=0;
		
		if(timer==5)
			UI_Percentage--;
		if(UI_Percentage<0)
			UI_Percentage=0;
	}
}
/***
                      O ON
					  X OFF
					  * BLINK
 discharing:   0%~25% O X X X
	          25%~50% O O X X
			  50%~75% O O O X
			 75%~100% O O O O
			 
	 charging: 0%~25% O * X X
	          25%~50% O O * X
			  50%~75% O O O *
			 75%~100% O O O O
***/
static void percentage_display()
{
	sync_UI_percentage();
	if(chr_det==TRUE)//for charging
	{
		if(UI_Percentage>=75)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Set(LED_SINK_3,LED_ON);
			Led_Sink_Set(LED_SINK_4,LED_ON);
		}
		else if(UI_Percentage>=50)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Set(LED_SINK_3,LED_ON);
			Led_Sink_Blink(LED_SINK_4,LED_BLINK_TIME_1000);
		}
		else if(UI_Percentage>=25)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Blink(LED_SINK_3,LED_BLINK_TIME_1000);
			Led_Sink_Set(LED_SINK_4,LED_OFF);
		}else if(UI_Percentage>0)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Blink(LED_SINK_2,LED_BLINK_TIME_1000);
			Led_Sink_Set(LED_SINK_3,LED_OFF);
			Led_Sink_Set(LED_SINK_4,LED_OFF);			
		}
	}else if(chr_det==FALSE)//for dis_charging
	{
		if(UI_Percentage>=75)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Set(LED_SINK_3,LED_ON);
			Led_Sink_Set(LED_SINK_4,LED_ON);
		}
		else if(UI_Percentage>=50)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Set(LED_SINK_3,LED_ON);
			Led_Sink_Set(LED_SINK_4,LED_OFF);
		}
		else if(UI_Percentage>=25)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_ON);
			Led_Sink_Set(LED_SINK_3,LED_OFF);
			Led_Sink_Set(LED_SINK_4,LED_OFF);
		}else if(UI_Percentage>0)
		{
			Led_Sink_Set(LED_SINK_1,LED_ON);
			Led_Sink_Set(LED_SINK_2,LED_OFF);
			Led_Sink_Set(LED_SINK_3,LED_OFF);
			Led_Sink_Set(LED_SINK_4,LED_OFF);			
		}
	}
}
uint8_t sleep_timer=0;
void check_need_sleep()
{
	if(phone_is_online==FALSE && pc_is_online==FALSE && charger_is_online ==FALSE)
		sleep_timer++;
	else 
		sleep_timer =0;
		
	if(sleep_timer==6)//about 60 seconds.
	{
		enter_stopmode();//go to sleep mode
		sleep_timer = 0;
	}
}
void battery_thread()
{		
	
	uart_printf("battery_thread:battery_run_timer=%d\n",battery_run_timer);
	if(battery_run_timer==TRUE)
	{
		percentage_display();
		if(chr_det==TRUE)
		{	
			mt_battery_charging_algorithm();
		}else{
			charging_state = CHR_PRE;
		}
		check_need_sleep();
	}
}
/* get battery voltage adc value */

void init_battery()
{
	/***[1] init ui_percentage***/
	percentage_display();
	/***[2] check pc or phone is online or outline***/
}

 

 

3、顯示模塊

這裡主要指的是4個led,4個led代表了電池的電量,主要就是實現了閃爍和亮滅,其驅動如下:

 

 

#include "stm32f0xx_hal.h"
#include "led.h"
//#include "stm32f0xx_it.h"
static uint16_t blink_led_type=1;
extern TIM_HandleTypeDef htim6;
extern TIM_HandleTypeDef htim14;

extern uint8_t battery_run_timer;
/* interrupt for timer6 callback*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==htim6.Instance)
	{
		if((blink_led_type==LED_SINK_1_Pin) || (blink_led_type==LED_SINK_2_Pin))
			HAL_GPIO_TogglePin(GPIOF, blink_led_type);
		else if((blink_led_type==LED_SINK_3_Pin) || (blink_led_type==LED_SINK_4_Pin))
			HAL_GPIO_TogglePin(GPIOA, blink_led_type);
	}
	if(htim->Instance==htim14.Instance)
	{
		battery_run_timer = TRUE;
	}
}
/* led set */
void Led_Sink_Set(enum tct_led_sink_type led_type,enum tct_led_state led_state)
{
    switch (led_type)
	{
		case LED_SINK_1:
			if(led_state==LED_ON)
				HAL_GPIO_WritePin(GPIOF, LED_SINK_1_Pin, GPIO_PIN_SET);
			else 
				HAL_GPIO_WritePin(GPIOF, LED_SINK_1_Pin, GPIO_PIN_RESET);
			break;
		case LED_SINK_2:
			if(led_state==LED_ON)
				HAL_GPIO_WritePin(GPIOF, LED_SINK_2_Pin, GPIO_PIN_SET);
			else
				HAL_GPIO_WritePin(GPIOF, LED_SINK_2_Pin, GPIO_PIN_RESET);
			break;
		case LED_SINK_3:
			if(led_state==LED_ON)
				HAL_GPIO_WritePin(GPIOA, LED_SINK_3_Pin, GPIO_PIN_SET);
			else
				HAL_GPIO_WritePin(GPIOA, LED_SINK_3_Pin, GPIO_PIN_RESET);
			break;
		case LED_SINK_4:
			if(led_state==LED_ON)
				HAL_GPIO_WritePin(GPIOA, LED_SINK_4_Pin, GPIO_PIN_SET);
			else
				HAL_GPIO_WritePin(GPIOA, LED_SINK_4_Pin, GPIO_PIN_RESET);
			break;
		default:
			break;
	}
}
/* led blink */
void Led_Sink_Blink(enum tct_led_sink_type led_type,enum tct_led_blink_time led_blink_time)
{
	if(led_blink_time==LED_BLINK_TIME_0)
		HAL_TIM_Base_Stop_IT(&htim6);//stop timer6
	else{
		htim6.Init.Prescaler = 0;//prescaler clock
		htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
		htim6.Init.Period = led_blink_time;//blink period
		
		HAL_TIM_Base_Start_IT(&htim6);//start timer6
	}
	switch (led_type)
	{
		case LED_SINK_1:
			blink_led_type=LED_SINK_1_Pin;
			break;
		case LED_SINK_2:
			blink_led_type=LED_SINK_2_Pin;
			break;
		case LED_SINK_3:
			blink_led_type=LED_SINK_3_Pin;
			break;
		case LED_SINK_4:
			blink_led_type=LED_SINK_4_Pin;
			break;
		default:
			break;
	}
}
/* led init */
 

 

4、調試模塊

這裡主要采用UART口進行打印調試,因此要在UART上實現類似c語言中的printf函數

 

 

#include 
#include 
#include "stm32f0xx_hal.h"
#include "print.h"

extern UART_HandleTypeDef huart1;
void uart_printf(char *fmt, ...)
{
	char      uart1_pString[101]; 
	va_list   uart1_ap;
	va_start(uart1_ap, fmt); 
	vsnprintf(uart1_pString, 100, fmt, uart1_ap);
	va_end(uart1_ap);
	HAL_UART_Transmit_IT(&huart1, (uint8_t *)uart1_pString, sizeof(uart1_pString));
}

 

 

 

4、睡眠模塊

單充電寶不使用時,系統需要進入待機模式,達到省電狀態,stm32f0主要包括了三種省電狀態

 

 

#include "stm32f0xx_hal.h"
#include "sleep.h"
uint8_t sleep_mode;

void enter_stopmode()
{
	sleep_mode =1;
	HAL_GPIO_WritePin(GPIOA, VDD33_HUB_EN_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA, VDD33_EN_Pin, GPIO_PIN_RESET);
	HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
 

由於項目暫停,PD狀態機的移植代碼還沒提供,因此沒有繼續開發下去,板子也沒到,因此也沒有在真實的板子上運行過,還有待驗證。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved