- UID
- 373967
- 帖子
- 8779
- 主題
- 2609
- 精華
- 0
- 積分
- 993
- 楓幣
- 2637
- 威望
- 970
- 存款
- 31556
- 贊助金額
- 0
- 推廣
- 0
- GP
- 1205
- 閱讀權限
- 50
- 在線時間
- 451 小時
- 註冊時間
- 2023-1-12
- 最後登入
- 2024-11-5
|
這個萬用充電器支援3V、5V、9V、12V、24V的充電,並且可以通過LCD顯示器顯示目前的電壓和電流值。
所需零件:
STM8S003F3P6單片機
16x2 LCD顯示器
5V電源供應器
10k歐姆電阻器
電位器
2N3904 NPN電晶體
1N4007整流二極管
按鈕開關
電阻、電容等基本零件
連接腳位:
rust
Copy code
LCD顯示器:
VSS -> GND
VDD -> 5V電源
V0 -> 電位器中間腳位
RS -> PB4
RW -> GND
E -> PB5
D4 -> PB0
D5 -> PB1
D6 -> PB2
D7 -> PB3
A -> 5V電源
K -> GND
按鈕開關:
1端 -> 5V電源
2端 -> PA3
NPN電晶體:
C極 -> 5V電源
B極 -> PA2
E極 -> 輸出端
整流二極管:
正極 -> 輸出端
負極 -> 5V電源
其他零件:
各種電阻、電容等基本零件按需使用
程式碼:
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "stm8s.h"
#include "stm8s_gpio.h"
#include "stm8s_tim1.h"
#include "stm8s_adc1.h"
#include "stm8s_clk.h"
#include "stm8s_lcd.h"
#define LCD_RS_PIN GPIO_PIN_4
#define LCD_RW_PIN GPIO_PIN_5
#define LCD_E_PIN GPIO_PIN_6
#define LCD_D4_PIN GPIO_PIN_0
#define LCD_D5_PIN GPIO_PIN_1
#define LCD_D6_PIN GPIO_PIN_2
#define LCD_D7_PIN GPIO_PIN_3
#define BUTTON_PIN GPIO_PIN_3
#define CHARGE_PIN GPIO_PIN_2
#define CHARGE_3V 511 // ADC測量到的3V電壓值
#define CHARGE_5V 817 // ADC測量到的5V電壓值
#define CHARGE_9V 1517 // ADC測量到的9V電壓值
#define CHARGE_12V 2046 // ADC測量到的12V電壓值
#define CHARGE_24V 4095 // ADC測量到的24V電壓值
#define LCD_ROW_1 0
#define LCD_ROW_2 1
#define LCD_COL_1 0
// 定義全局變量
uint16_t charge_voltage = 0; // 充電器輸出電壓
uint16_t charge_current = 0; // 充電器輸出電流
bool button_pressed = false; // 按鈕是否按下
bool charging = false; // 是否正在充電
bool charged = false; // 是否充滿電
bool over_current = false; // 是否過流
bool over_voltage = false; // 是否過壓
uint16_t over_current_count = 0; // 過流計數器
uint16_t over_voltage_count = 0; // 過壓計數器
// 定義函數
void init_lcd(void);
void display_voltage(void);
void display_current(void);
void check_button(void);
void check_over_current(void);
void check_over_voltage(void);
void start_charge(void);
void stop_charge(void);
// 主函數
void main(void)
{
// 初始化單片機
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // 將主時鐘頻率設置為16MHz
GPIO_DeInit(GPIOA);
GPIO_DeInit(GPIOB);
LCD_DeInit();
TIM1_DeInit();
ADC1_DeInit();
// 初始化GPIO口
GPIO_Init(GPIOA, BUTTON_PIN, GPIO_MODE_IN_PU_NO_IT); // 配置按鈕口為上拉輸入
GPIO_Init(GPIOA, CHARGE_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置充電器控制口為推挽輸出
GPIO_Init(GPIOB, LCD_RS_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD RS口為推挽輸出
GPIO_Init(GPIOB, LCD_RW_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD RW口為推挽輸出
GPIO_Init(GPIOB, LCD_E_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD E口為推挽輸出
GPIO_Init(GPIOB, LCD_D4_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD D4口為推挽輸出
GPIO_Init(GPIOB, LCD_D5_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD D5口為推挽輸出
GPIO_Init(GPIOB, LCD_D6_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD D6口為推挽輸出
GPIO_Init(GPIOB, LCD_D7_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 配置LCD D7口為推挽輸出
// 初始化LCD顯示器
init_lcd();
// 初始化定時器1,用於ADC采樣
TIM1_TimeBaseInit(0, TIM1_COUNTERMODE_UP, 63, 0);
TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE);
TIM1_Cmd(ENABLE);
// 測量充電器輸出電壓和電流
while (1)
{
if (charging)
{
// 檢查是否過流或過壓
check_over_current();
check_over_voltage();
if (over_current || over_voltage)
{
// 如果過流或過壓,停止充電
stop_charge();
}
else
{
// 否則繼續充電
GPIO_WriteHigh(GPIOA, CHARGE_PIN); // 打開充電器
ADC1_StartConversion();
while (!ADC1_GetFlagStatus(ADC1_FLAG_EOC))
{
// 等待ADC轉換完成
}
charge_voltage = ADC1_GetConversionValue(); // 獲取充電器輸出電壓
display_voltage();
charge_current = ADC1_GetConversionValue(); // 獲取充電器輸出電流
display_current();
if (charge_current < CHARGE_CURRENT_THRESHOLD && charge_voltage >= CHARGE_VOLTAGE_THRESHOLD)
{
// 如果充電電流小於閾值且充電電壓大於閾值,表示充滿電了
charged = true;
stop_charge();
}
}
}
else
{
// 檢查按鈕是否按下,如果按下就開始充電
check_button();
if (button_pressed)
{
start_charge();
}
}
}
}
// 初始化LCD顯示器
void init_lcd(void)
{
LCD_Init(LCD_DISPLAY_ON_CURSOR_OFF_BLINK_OFF);
LCD_Clear();
LCD_GotoXY(0, 0);
LCD_SendString("Charge voltage:");
LCD_GotoXY(0, 1);
LCD_SendString("Charge current:");
}
// 顯示充電器輸出電壓
void display_voltage(void)
{
char buffer[16];
LCD_GotoXY(15, 0);
sprintf(buffer, "%d.%02dV", charge_voltage / 100, charge_voltage % 100);
LCD_SendString(buffer);
}
// 顯示充電器輸出電流
void display_current(void)
{
char buffer[16];
LCD_GotoXY(15, 1);
sprintf(buffer, "%d.%02dA", charge_current / 100, charge_current % 100);
LCD_SendString(buffer);
}
// 檢查按鈕是否按下
void check_button(void)
{
if (GPIO_ReadInputPin(GPIOA, BUTTON_PIN) == RESET)
{
button_pressed = true;
while (GPIO_ReadInputPin(GPIOA, BUTTON_PIN) == RESET)
{
// 等待按鈕釋放
}
}
else
{
button_pressed = false;
}
}
// 檢查是否過流
void check_over_current(void)
{
if (charge_current > OVER_CURRENT_THRESHOLD)
{
over_current_count++;
if (over_current_count > OVER_CURRENT_COUNT_THRESHOLD)
{
over_current = true;
over_current_count = 0;
}
}
else
{
over_current_count = 0;
}
// 檢查是否過壓
void check_over_voltage(void)
{
if (charge_voltage > OVER_VOLTAGE_THRESHOLD)
{
over_voltage_count++;
if (over_voltage_count > OVER_VOLTAGE_COUNT_THRESHOLD)
{
over_voltage = true;
over_voltage_count = 0;
}
}
else
{
over_voltage_count = 0;
}
}
// 停止充電
void stop_charge(void)
{
GPIO_WriteLow(GPIOA, CHARGE_PIN); // 關閉充電器
charging = false;
over_current = false;
over_voltage = false;
}
// 開始充電
void start_charge(void)
{
charged = false;
charging = true;
}
// 初始化ADC
void init_adc(void)
{
ADC1_DeInit();
ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_2, ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);
ADC1_Cmd(ENABLE);
}
// 初始化按鈕和充電器引腳
void init_pins(void)
{
GPIO_Init(BUTTON_PORT, BUTTON_PIN, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init(GPIOA, CHARGE_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
}
// 初始化計時器
void init_timer(void)
{
TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4_Cmd(ENABLE);
}
// 計時器中斷處理函數
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
{
TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
if (charging && !charged)
{
time_count++;
if (time_count > CHARGE_TIME_THRESHOLD)
{
stop_charge();
}
}
}
// 主程序
void main(void)
{
// 初始化
init_pins();
init_adc();
init_timer();
enableInterrupts();
// 主循環
while (1)
{
// 檢查按鈕是否按下
if (GPIO_ReadInputPin(BUTTON_PORT, BUTTON_PIN) == RESET)
{
// 開始充電
start_charge();
GPIO_WriteHigh(GPIOA, CHARGE_PIN); // 開啟充電器
}
// 檢查是否充滿
if (charged)
{
stop_charge();
}
// 檢查是否過電流
check_over_current();
// 檢查是否過壓
check_over_voltage();
}
}
至於具體的硬體連接腳位,可以根據所使用的萬用板或硬體模組進行對應設置。
需要注意的是,由於不同的硬體模組或萬用板可能采用不同的引腳定義方式,因此需要根據具體的情況進行修改。 |
|