记录一下我的车载嵌入式学习过程
1.利用stm32采集电压数据,使用can协议发送,之后使用pcan在pc端查看采集到的数据。
下图是在电脑上查看采集到的电压数据


注意要设置好,波特率,确保烧录进单片机的波特率和软件中的波特率保持一致,不然无法显示,因为波特率设置不一致的时候,pcan分析仪会导致
-
帧起始(SOF)或帧结束(EOF)识别错误。
-
CRC校验失败,接收方丢弃数据帧。
-
位填充错误,触发错误帧(Error Frame),总线进入错误恢复状态
所以没有数据显示
2.滑动滤波算法,保持电压稳定
/* ADC滤波算法(优化初始化) */
uint16_t ADC_GetValue(void) {
static uint16_t buffer[8] = {0};
static uint8_t index = 0;
static uint32_t sum = 0;
static uint8_t initialized = 0;
uint16_t raw = ADC_GetConversionValue(ADC1);
/* 首次运行初始化缓冲区 */
if(!initialized) {
for(uint8_t i=0; i<8; i++) {
buffer[i] = raw;
sum += raw;
}
initialized = 1;
}
sum -= buffer[index];
buffer[index] = raw;
sum += raw;
index = (index + 1) % 8;
return sum / 8;
}
3.使用看门狗检测程序是否卡死,如果卡死程序复位
4.当电压低于0.8V的时候可以进入低功耗模式,不过有个小问题没有解决,就是进入低功耗模式后任何中断源都可以唤醒系统,系统进入低功耗模式只能进入一秒,然后就被唤醒,需要解决,我明天再继续修改。
这是完整的程序,后续会接着改。
#include "stm32f10x.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* 硬件配置 */
#define LED_PIN GPIO_Pin_13
#define LED_PORT GPIOC
#define CAN_ID_ADC 0x123
#define LOW_POWER_THRESHOLD 1000 // ADC阈值约0.8V
#define OLED_LINE_ADC 1 // ADC值显示行
#define OLED_LINE_VOLT 2 // 电压值显示行
/* 校准参数(需实际测量) */
#define VREF_MEASURED 3.28f // 实测VDDA电压(用万用表测量)
#define ADC_MAX 4095 // ADC满量程值
/* OLED显示函数声明 */
void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
/* 全局变量 */
volatile uint32_t sysTick = 0; // 系统滴答计数器
/* 函数原型 */
void Delay_ms(uint32_t ms);
void Hardware_Init(void);
uint16_t ADC_GetValue(void);
float ADC_ToVoltage(uint16_t adcVal);
void CAN_SendFrame(uint32_t id, uint8_t* data, uint8_t len);
void Enter_LowPower_Mode(void);
/* 系统滴答中断 */
void SysTick_Handler(void) {
sysTick++;
}
/* 获取系统时间戳 */
uint32_t GetTick(void) {
return sysTick;
}
int main(void) {
Hardware_Init();
uint32_t lastADC = 0;
uint32_t lastRefresh = 0;
/* OLED显示初始化 */
OLED_Clear();
OLED_ShowString(OLED_LINE_ADC, 1, "ADC:");
OLED_ShowString(OLED_LINE_VOLT, 1, "VOLT:");
GPIO_SetBits(GPIOA, GPIO_Pin_2);
while(1) {
/* 1秒读取ADC并发送CAN */
if(GetTick() - lastADC >= 5000) {
lastADC = GetTick();
uint16_t adcVal = ADC_GetValue();
uint8_t data[2] = {adcVal & 0xFF, (adcVal >> 8) & 0xFF};
CAN_SendFrame(CAN_ID_ADC, data, 2);
if(adcVal < LOW_POWER_THRESHOLD) {
Enter_LowPower_Mode();
Delay_ms(5000);
}
}
/* 200ms刷新OLED */
if(GetTick() - lastRefresh >= 200) {
lastRefresh = GetTick();
uint16_t adcVal = ADC_GetValue();
float voltage = ADC_ToVoltage(adcVal);
/* 显示ADC值和电压 */
OLED_ShowNum(OLED_LINE_ADC, 6, adcVal, 4);
char voltStr[16];
sprintf(voltStr, "%.2fV", voltage);
OLED_ShowString(OLED_LINE_VOLT, 6, voltStr);
}
/* 喂狗 */
IWDG_ReloadCounter();
}
}
/* 硬件初始化 */
void Hardware_Init(void) {
/* 系统时钟初始化 */
SystemInit();
SysTick_Config(SystemCoreClock / 1000);
/* 启用外设时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC |
RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* LED初始化(PC13) */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC初始化(PA0) */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
/* CAN初始化(PA11/RX, PA12/TX) */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStruct);
CAN_InitTypeDef CAN_InitStruct;
CAN_StructInit(&CAN_InitStruct);
CAN_InitStruct.CAN_Mode = CAN_Mode_Normal;
CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;
CAN_InitStruct.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStruct.CAN_BS2 = CAN_BS2_7tq;
CAN_InitStruct.CAN_Prescaler = 4; // 500bps
CAN_Init(CAN1, &CAN_InitStruct);
/* 看门狗初始化(1秒超时) */
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_32);
IWDG_SetReload(1250);
IWDG_ReloadCounter();
IWDG_Enable();
/* OLED初始化 */
OLED_Init();
}
/* ADC滤波算法(优化初始化) */
uint16_t ADC_GetValue(void) {
static uint16_t buffer[8] = {0};
static uint8_t index = 0;
static uint32_t sum = 0;
static uint8_t initialized = 0;
uint16_t raw = ADC_GetConversionValue(ADC1);
/* 首次运行初始化缓冲区 */
if(!initialized) {
for(uint8_t i=0; i<8; i++) {
buffer[i] = raw;
sum += raw;
}
initialized = 1;
}
sum -= buffer[index];
buffer[index] = raw;
sum += raw;
index = (index + 1) % 8;
return sum / 8;
}
/* 精确电压计算(基于实测VREF) */
float ADC_ToVoltage(uint16_t adcVal) {
return (adcVal * VREF_MEASURED) / ADC_MAX;
}
/* CAN数据发送 */
void CAN_SendFrame(uint32_t id, uint8_t* data, uint8_t len) {
CanTxMsg txMsg;
txMsg.StdId = id;
txMsg.IDE = CAN_Id_Standard;
txMsg.RTR = CAN_RTR_Data;
txMsg.DLC = len;
memcpy(txMsg.Data, data, len);
CAN_Transmit(CAN1, &txMsg);
while(CAN_TransmitStatus(CAN1, CAN_FIFO0) != CAN_TxStatus_Ok);
}
/* 进入低功耗模式 */
void Enter_LowPower_Mode(void) {
GPIO_ResetBits(LED_PORT, 13);
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, DISABLE);
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
Delay_ms(5000);
// SystemInit();
// SystemCoreClockUpdate();
// Hardware_Init();
}
///* 简单延时函数 */
//void Delay_ms(uint32_t ms) {
// uint32_t start = GetTick();
// while(GetTick() - start < ms);
//}
1万+

被折叠的 条评论
为什么被折叠?



