逆向设计!用STM32伪装成ADC芯片
事件背景
课程设计,同学抽到的题目是用单片机做万用表。但他没学好,是直接几百块买了淘宝上设计好的套件,用的是STC和ADC0832……然后他在检查日的前两天把玩的时候把ADC芯片烧了(到这里我才知道为什么要额外使用ADC芯片,使用麻烦精度又低),淘宝买来不及了。
学校教的是STM32,51单片机编程我也不会。突发奇想用STM32读取电压,伪装成ADC芯片把读数发给51单片机。正好老师允许拍成视频发给他检查,我的那一套STM32摆在画框外面也不至于逆向工程喧宾夺主了。
道路曲折
逻辑分析
找来了ADC0832的手册,看着时序图用Arduino两下把程序写好了。烧录,连线,不出意外的第一次是不会正常工作的。
找来逻辑分析仪打了一下看,反正折腾了一晚上没搞懂。第二天再研究,才想起要看看51的代码是怎么写的,又问同学要了店家给的代码。
“你是不是改过代码?”
“没有啊”
“卖家应该会给代码吧?就是把他原版的给我”
“这个就是啊!”
…………
水落石出
这个代码根本不符合ADC0832的时序,最后我根据这个错误的代码和逻辑分析仪的结果,写了Arduino。跑通了,而我也确信了这个店家在做这个项目的时候也是一知半解,不知道为什么没跑通,又为什么跑通了,既然跑通就能卖给大学生了。
最后成功让万用表能测试电压电流了。
源码
因为这个代码是给有BUG的51代码设计的,而且没有正确调用ADC0832的信号作为测试,又懒得再调试完整实现ADC0832的功能,以下代码混写了Arduino和HAL库,仅供参考,提供思路。
#include <Arduino.h>
const int adc0 = PA0, fake_clk = PA15, fake_io = PA11, fake_cs = PA9;
const int debug_pin = PC13;
const float Vref = 3.3, adc0_Vmax = 2.857, correct_scal = 0.969;
const float adc_adjust = adc0_Vmax / Vref * correct_scal;
typedef enum
{
CH0,
CH1,
none
} CHx;
uint8_t CS = HIGH;
uint8_t ch_selected = CH0;
int adc_val = 0;
float adc_norm;
uint8_t fake_reg_ch0 = 0, fake_reg_ch1 = 0, fake_reg_ch0_reverse = 0;
void cs_callback();
bool wait_clkrising();
bool wait_clkfalling();
uint8_t bit_reverse(uint8_t x);
void setup()
{
// noInterrupts();
attachInterrupt(fake_cs, cs_callback, FALLING);
pinMode(fake_cs, INPUT_PULLUP);
// interrupts();
pinMode(fake_clk, INPUT_PULLDOWN);
pinMode(fake_io, INPUT);
pinMode(debug_pin, OUTPUT);
digitalWrite(debug_pin, HIGH);
Serial2.begin(115200);
}
void loop()
{
adc_val = analogRead(adc0);
adc_norm = adc_val / (1023.0 * adc_adjust);
// Serial2.println(adc_val);
// Serial2.println(adc_norm);
if (adc_norm < 0.1)
{
fake_reg_ch0_reverse = 0U;
}
else
{
fake_reg_ch0_reverse = bit_reverse(128U);
}
// if (adc_norm > 1)
// {
// fake_reg_ch0 = 255;
// }
// else
// {
// fake_reg_ch0 = (adc_norm * 255.0) + 0.5;
// fake_reg_ch0_reverse = bit_reverse(fake_reg_ch0);
// }
// Serial2.println(fake_reg_ch0);
Serial2.println((fake_reg_ch0 / 255.0) * 20.0);
Serial2.println(fake_reg_ch0);
delay(200);
}
void cs_callback()
{
do
{
if (digitalRead(fake_cs != LOW))
break;
wait_clkfalling(); // 1
wait_clkfalling(); // 3
// if (digitalRead(fake_io) != LOW) // 选择通道
// break;
// wait_clkfalling(); // 3
// if (digitalRead(fake_io) != HIGH) // 我也不知道干嘛,51的程序有误
// break;
// ch_selected = digitalRead(fake_io);
digitalToggle(debug_pin);
pinMode(fake_io, OUTPUT);
// digitalWrite(fake_io, LOW);
// for (uint8_t i = 7; i > 0; i--)
// {
// wait_clkfalling();
// digitalWrite(fake_io, bitRead(fake_reg_ch0, i));
// // digitalToggle(debug_pin); // debug
// }
// digitalToggle(debug_pin); // debug
for (uint8_t i = 0; i < 8; i++)
{
digitalWrite(fake_io, bitRead(fake_reg_ch0_reverse, i));
wait_clkfalling();
}
// wait_clkfalling();
// digitalToggle(debug_pin); // debug
} while (0);
// digitalToggle(debug_pin); // debug
pinMode(fake_io, INPUT);
}
bool wait_clkrising()
{
// while(digitalRead(fake_clk) == HIGH);
// while(digitalRead(fake_clk) == LOW);
uint32_t time_start = HAL_GetTick();
while (LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_15) == HIGH)
{
if ((HAL_GetTick() - time_start) > 1)
return false;
}
while (LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_15) == LOW)
{
if ((HAL_GetTick() - time_start) > 1)
return false;
}
return true;
}
bool wait_clkfalling()
{
// while (digitalRead(fake_clk) == LOW);
// while (digitalRead(fake_clk) == HIGH);
uint32_t time_start = HAL_GetTick();
while (LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_15) == LOW)
{
if ((HAL_GetTick() - time_start) > 1)
return false;
}
while (LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_15) == HIGH)
{
if ((HAL_GetTick() - time_start) > 1)
return false;
}
return true;
}
uint8_t bit_reverse(uint8_t x)
{
x = (((x & 0xaa) >> 1) | ((x & 0x55) << 1));
x = (((x & 0xcc) >> 2) | ((x & 0x33) << 2));
return ((x >> 4) | (x << 4));
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体