切换到宽版
爱科技/爱创意/爱折腾/爱极致;技术知识分享平台,点击进入新版数码之家网站
  • 16742阅读
  • 50回复

[电源]谁说壁虎没用?用efm32做个USB电压电流表(可诱导QC2.0) [复制链接]

上一主题 下一主题
离线2545889167
 

发帖
13268
M币
20754
专家
302
粉丝
4860
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2016-06-16
— 本帖被 香瑶 设置为精华,作者+3000M币+5专家(2016-07-11) —
在疯狂的撸pos的过程中,坛友看重的最多是电池,紧接着就是stm32/gd32单片机,而核心为efm32一派的pos机,因为资料少,没调试工具,就被打上了:没卵用,垃圾,便宜货等等的名号,被大家仍在墙角堆灰。为了利用上这只小壁虎,于是乎为决定研究研究。
开始入门是照着@kanamu 大神的帖子来的,玩了几天,觉得壁虎的adc性能不错(1msps,12bit,4ch,内部1.25/2.5v的bandgap基准,输入阻抗高,可以差分输入),于是就有了这个usb小表的小项目。
然后从学习点亮第一个LED灯到现在,掐指一算,应该就两个星期的零碎时间搞起来了。
好的,不啰嗦了,开始

如果想要学习的话,两个东西必备,首先要一个jlink。怎么?没有jlink?用pos机做一个呗,只要一块钱
【教程】用gd32做一个jlink-ob调试器,并吊打壁虎(efm32)|http://bbs.mydigit.cn/read.php?tid=1692562
然后开发环境,我选择的是官方提供的simplicity-studio,图形化的开发环境,很简单的说,点几下,选一下就可以玩了,不过有些坛友说太大难下载,这个嘛,我也帮不了你了,我这里下载能到100兆帕的样子(偷笑)
下载地址:http://cn.silabs.com/products/mcu/Pages/simplicity-studio.aspx
网速快的可以先现在在线端,然后补充对应型号的库就好了,这样省空间点

当然我这个小表现在的状态还是原型样机,验证阶段。没有任何显示装置,电压电流靠串口回传的,本来搞好了数码管,但懒得飞线焊上,那就将就下了,自用无所谓了


小表和jlink的整套合影,简单粗糙啊真是

中间飞了一堆线

壁虎efm32单片机特写

这个是usb部分焊好的电路,双面洞洞板真是个折磨人的小妖精啊



qc2.0诱导试验
诱导开始前,电压5v,红灯亮

诱导成功,输出9v,因为我这个充电头没有12v档,就没测了


简单说一下qc2.0的协议,手机在d+上加0.6v电压,这时充电器内部d+和d-是联通的,d-也是0.6v,在1.35秒后,充电器断开d+和d-的联通,d-电压降到0,这时表示充电器支持协议,接下来就是手机请求电压,在d+加3.3v,d-加0.6v时,输出9v,在d+加0.6v,d-加0.6v时,输出12v,在d+加3.3v,d-加3.3v时,输出20v,在d+加0.6v,d-加0v时,输出5v,然后就可以靠这协议来骗一把充电器了。在d+上我用dac直接实现,这很方便,d-上接adc,同时有一个引脚推挽输出高,10k和2.2k分压为0.6v,这样就可以让充电器输出9v了,18w功率可是爽歪歪啊。

电压电流测试
电流取样电阻因为手头只有100毫欧的,只能硬头皮上了,虽然好像真的有点大了。
目前串口值是原始数据,不过波动不算太大
5v时给手机充电,电压0x640左右,换算为5.08v
电流为0xae左右,500ma左右

诱导为9v时,因为我没有合适负载,所以电流数据是0了,就测了下电压0xB2f左右,9.08v的样子

这个值有点偏低的问题,是adc有点偏低,之前测试了整个量程,大概偏了一个f的样子,具体原因不是很清楚,可能也和电路有关,不过偏的比较线性,后面可以校准,输出值波动不大,这倒是个好事。

最后上电路图,简易的

当然以上要保证最小系统正常,因为实验阶段是在pos板子上改的,就没必要理,不过还是贴张最小系统的图

仿制难度应该不大,就是太简单太low了,不过想玩qc2.0的可以试试
我贴下源代码,真的不长,不过没注释,我太懒了
其实,真心,这货的现在的难度,就是点几下鼠标,然后后面的操作就很简单了,已经有点类似arduino的感觉了
  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "em_usart.h"
  4. #include "em_device.h"
  5. #include "em_chip.h"
  6. #include "InitDevice.h"
  7. #include "em_cmu.h"
  8. #include "em_gpio.h"
  9. #include "stdio.h"
  10. #include "em_emu.h"
  11. #include "em_adc.h"
  12. #include "em_dac.h"
  13. void sys_int(void)
  14. {
  15.     CHIP_Init();
  16.     /* Infinite loop */
  17.     enter_DefaultMode_from_RESET();
  18.     //GPIO_PinOutClear(gpioPortA, 8);
  19.     /*串口进中断*/
  20.     USART0->IFC = _USART_IFC_MASK;
  21.     NVIC_ClearPendingIRQ(USART0_RX_IRQn);
  22.     NVIC_EnableIRQ(USART0_RX_IRQn);
  23.     USART0->IEN = USART_IEN_RXDATAV;
  24.     USART0->ROUTE |=  USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_LOCATION_LOC0;
  25.     /*串口进中断结束*/
  26.     /* Enable DAC channel 0, located on pin PB11 */
  27.     DAC_Enable(DAC0, 0, true);
  28. }
  29. /**************************************************************************//**
  30. * [url=u.php?uid=650075]@brief[/url]    Write DAC conversion value
  31. *****************************************************************************/
  32. void DAC_WriteData(DAC_TypeDef *dac, unsigned int value, unsigned int ch)
  33. {
  34.     /* Write data output value to the correct register. */
  35.     if (!ch)
  36.     {
  37.         dac->CH0DATA = value;
  38.     }
  39.     else
  40.     {
  41.         dac->CH1DATA = value;
  42.     }
  43. }
  44. uint32_t ADC0_get_result()
  45. {
  46.     uint32_t samp;
  47.     ADC_Start(ADC0, adcStartSingle);
  48.     /* Wait while conversion is active */
  49.     while (ADC0->STATUS & ADC_STATUS_SINGLEACT) ;
  50.     /* Get ADC result */
  51.     samp = ADC_DataSingleGet(ADC0);
  52.     return samp;
  53. }
  54. uint32_t ADC0_get_send_result()
  55. {
  56.     uint32_t samp;
  57.     uint8_t cache1 = 0;
  58.     uint8_t cache = 0;
  59.     uint32_t cache2 = 0;
  60.     samp = ADC0_get_result();
  61.     cache2 = samp;
  62.     cache1 = samp;
  63.     samp >>= 8;
  64.     cache = samp;
  65.     USART_Tx(USART0, cache);
  66.     USART_Tx(USART0, cache1);
  67.     return cache2;
  68. }
  69. void adc_change_input_ch(uint8_t ch)
  70. {
  71.     ADC_InitSingle_TypeDef initsingle = ADC_INITSINGLE_DEFAULT;
  72.     switch(ch)
  73.     {
  74.     case 4:
  75.         initsingle.prsSel = adcPRSSELCh0;
  76.         initsingle.acqTime = adcAcqTime64;
  77.         initsingle.reference = adcRef1V25;
  78.         initsingle.resolution = adcRes12Bit;
  79.         initsingle.input = adcSingleInpCh4;
  80.         initsingle.diff = 0;
  81.         initsingle.prsEnable = 0;
  82.         initsingle.leftAdjust = 0;
  83.         initsingle.rep = 0;
  84.         ADC_InitSingle(ADC0, &initsingle);
  85.         break;
  86.     case 5:
  87.         initsingle.prsSel = adcPRSSELCh0;
  88.         initsingle.acqTime = adcAcqTime64;
  89.         initsingle.reference = adcRef1V25;
  90.         initsingle.resolution = adcRes12Bit;
  91.         initsingle.input = adcSingleInpCh5;
  92.         initsingle.diff = 0;
  93.         initsingle.prsEnable = 0;
  94.         initsingle.leftAdjust = 0;
  95.         initsingle.rep = 0;
  96.         ADC_InitSingle(ADC0, &initsingle);
  97.         break;
  98.     case 6:
  99.         initsingle.prsSel = adcPRSSELCh0;
  100.         initsingle.acqTime = adcAcqTime64;
  101.         initsingle.reference = adcRef1V25;
  102.         initsingle.resolution = adcRes12Bit;
  103.         initsingle.input = adcSingleInpCh6;
  104.         initsingle.diff = 0;
  105.         initsingle.prsEnable = 0;
  106.         initsingle.leftAdjust = 0;
  107.         initsingle.rep = 0;
  108.         ADC_InitSingle(ADC0, &initsingle);
  109.         break;
  110.     }
  111. }
  112. /**************************************************************************//**
  113. * [url=u.php?uid=650075]@brief[/url]    Main function
  114. *****************************************************************************/
  115. int main(void)
  116. {
  117.     int i;
  118.     uint32_t sample;
  119.     uint8_t working_satae = 1;//0-普通5v  //1-qc2.0插入前  //2-qc2.0前奏   //3-qc2.0-9v
  120.     uint32_t DAC_Value;
  121.     sys_int();
  122.     while (1)
  123.     {
  124.         switch(working_satae)
  125.         {
  126.             case 0:
  127.             {
  128.                 for(i = 0; i < 20000; i++);
  129.                 DAC_Enable(DAC0, 0, 0);
  130.                 adc_change_input_ch(4);
  131.                 ADC0_get_send_result();
  132.                 adc_change_input_ch(6);
  133.                 ADC0_get_send_result();
  134.                 break;
  135.             }//case 0
  136.             case 1:
  137.             {
  138.                 for(i = 0; i < 20000; i++);
  139.                 DAC_Value = 0x2e8;
  140.                 DAC_WriteData(DAC0, DAC_Value, 0);
  141.                 adc_change_input_ch(4);
  142.                 ADC0_get_send_result();
  143.                 adc_change_input_ch(6);
  144.                 ADC0_get_send_result();
  145.                 adc_change_input_ch(5);
  146.                 sample =  ADC0_get_result();
  147.                 if(sample > 0x600 )
  148.                 {
  149.                     for(i = 0; i < 200; i++);
  150.                     adc_change_input_ch(5);
  151.                     sample =  ADC0_get_result();
  152.                     if(sample > 0x600 )
  153.                     {
  154.                         working_satae = 2;
  155.                     }
  156.                 }
  157.                 break;
  158.             }
  159.             case 2:
  160.             {
  161.                 DAC_Enable(DAC0, 0, 1);
  162.                 for(i = 0; i < 20000; i++);
  163.                 DAC_Value = 0x2e8;
  164.                 DAC_WriteData(DAC0, DAC_Value, 0);
  165.                 adc_change_input_ch(4);
  166.                 ADC0_get_send_result();
  167.                 adc_change_input_ch(6);
  168.                 ADC0_get_send_result();
  169.                 adc_change_input_ch(5);
  170.                 sample =  ADC0_get_result();
  171.                 if(sample < 0xd0 )
  172.                 {
  173.                     for(i = 0; i < 20000; i++);
  174.                     adc_change_input_ch(5);
  175.                     sample =  ADC0_get_result();
  176.                     if(sample < 0xd0 )
  177.                     {
  178.                         GPIO_PinOutSet(gpioPortA, 8);
  179.                         GPIO_PinModeSet(gpioPortE, 13, gpioModePushPullDrive, 1);
  180.                         GPIO_PinOutSet(gpioPortE, 13);
  181.                         DAC_Value = 0xfff;
  182.                         DAC_WriteData(DAC0, DAC_Value, 0);
  183.                         GPIO_PinOutClear(gpioPortA, 9);
  184.                         working_satae = 3;
  185.                     }
  186.                     else
  187.                     {
  188.                         GPIO_PinOutClear(gpioPortA, 8);
  189.                         GPIO_PinOutSet(gpioPortA, 9);
  190.                         GPIO_PinOutClear(gpioPortE, 13);
  191.                         GPIO_PinModeSet(gpioPortE, 13, gpioModeInput, 0);
  192.                     }
  193.                 }
  194.                 break;
  195.             }//case 1
  196.             case 3:
  197.             {
  198.                 DAC_Enable(DAC0, 0, 1);
  199.                 for(i = 0; i < 20000; i++);
  200.                 adc_change_input_ch(4);
  201.                 ADC0_get_send_result();
  202.                 adc_change_input_ch(6);
  203.                 ADC0_get_send_result();
  204.                 adc_change_input_ch(5);
  205.                 sample = ADC0_get_result();
  206.                 if(sample > 0x7a0)
  207.                 {
  208.                     for(i = 0; i < 20000; i++);
  209.                     //adc_change_input_ch(5);
  210.                     sample =  ADC0_get_result();
  211.                     if(sample > 0x780)
  212.                     {
  213.                     working_satae = 1;
  214.                     GPIO_PinOutClear(gpioPortA, 8);
  215.                     GPIO_PinOutSet(gpioPortA, 9);
  216.                     GPIO_PinOutClear(gpioPortE, 13);
  217.                     GPIO_PinModeSet(gpioPortE, 13, gpioModeInput, 0);
  218.                     }
  219.                 }
  220.                 break;
  221.             }//case 2
  222.         }
  223.     }
  224. }

代码上传到githbub了,怕你们看不到,特意把这行大号字体标红https://github.com/posystorage/USB-voltmeter


最后的口头禅,壁虎手册这么好看,你们还不来玩


最后的最后,说下这个usb小表后期的改进计划
0、如果有一定数量的坛友对这个项目感兴趣或者也想玩一发的,我会画pcb并把这货做成个产品级别的东西,如果没有,那项目就到这了,我也玩够了,壁虎还有其他好玩的呢。
如果项目继续,几方面计划
1、增加显示装置,估计会设计成数码管与oled兼容款pcb,低端数码管,高大上oled
2、现在快速充电协议那么多,除了qc2.0还有qc3.0、mtk-pe、海思快充、蓝绿大厂的快充等等等等。多支持几个是比较好玩的,也是大家喜闻乐见的。但是这有前提,首先要有资料,协议资料这还是比较麻烦的,很难找。还有就是要有对应的实验样品,快充充电头都比较贵,一个40-50的样子有些估计还不止,我一穷学生,还是搞不起这么多快充头。所以如果团购的话,就算PCB可能很便宜,就几毛一片,平摊这些费用后,估计要3-5元的一小片样子,先说明。
3、取样电阻由100毫欧改成10毫欧,然后配一枚运放。
4、原始数据要处理,平滑,校准偏差什么的
5、整个充电过程数据记录到单片机内部。这货有128k的程序空间,现在就用了7k的大小,最终完成可以最多用四分之一,后面剩余的大量空间可以记录充电过程数据,当然也会有专门的上传机制什么的,传到电脑可分析,这个再说。

就这些,欢迎砸m币



@zty615 坛友的作品:不用程序 只用通用零件装出QC2.0诱骗器,公布网络上你搜不出来的技术细节(完美完结):http://bbs.mydigit.cn/read.php?tid=1734268
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共45条打赏M币+140
关键词: efm32QC2.0
离线jpdd521

发帖
25693
M币
8005
专家
15
粉丝
350
只看该作者 1楼 发表于: 2016-06-16
请登录后查看
离线xazjg1

发帖
21072
M币
3041
专家
-1
粉丝
53
只看该作者 2楼 发表于: 2016-06-16
请登录后查看
离线客串而已

发帖
20416
M币
20921
专家
2
粉丝
17
只看该作者 3楼 发表于: 2016-06-16
请登录后查看
离线搅搅震

发帖
8831
M币
7012
专家
3
粉丝
43
只看该作者 4楼 发表于: 2016-06-16
请登录后查看
离线eliswee

发帖
134
M币
-1
专家
0
粉丝
2
只看该作者 5楼 发表于: 2016-06-16
请登录后查看
离线fm999

发帖
148
M币
469
专家
3
粉丝
51
只看该作者 6楼 发表于: 2016-06-16
请登录后查看
本帖最近打赏记录:共1条打赏M币+3
离线x3159

发帖
13395
M币
6654
专家
1
粉丝
39
只看该作者 7楼 发表于: 2016-06-16
请登录后查看
离线2545889167

发帖
13268
M币
20754
专家
302
粉丝
4860
只看该作者 8楼 发表于: 2016-06-16
回 搅搅震 的帖子
请登录后查看
离线lover520yd

发帖
585
M币
831
专家
3
粉丝
23
只看该作者 9楼 发表于: 2016-06-16
请登录后查看
快速回复
限80 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个