zoukankan      html  css  js  c++  java
  • 从头调试stm32 HID

    目录:
    第1部分:参照“正点原子USB虚拟串口工程移植步骤”移植ST的USB HID工程(失败了);
    第2部分:在1的基础上,替换USB HID初始化代码为ST 例程中的代码,编译后根据报错调试(失败了);
    第3部分:直接移植ST的USB HID工程,根据报错调试代码(成功了)。
     
        小孙想要总结这一年来学到的关于stm32的USB相关知识,但又不知道怎么总结,于是决定
    从头开始调试固件库代码,直到实现USB功能为止!
        首先准备参照正点原子《第88讲 USB虚拟串口实验-M3》,把HID相关库包含进工程中,工
    程选用正点原子的USART试验。因为目前手里的开发板是“微雪电子”的stm32f103cbt6开发板,
    硬件串口为:USART1(PA9和PA10)和SART2(PA2和PA3)。准备先把正点原子《实验4-串口
    实验》实例代码移植到这款开发板上,好方便以后调试使用。
        因为正点原子stm32f1开发板使用的晶振和手里的开发板一样都是8M的,所以在Keil里直接修
    改MCU型号和Flash大小后准备编译下载。没有报错。
        
     查看代码中串口初始化函数,发现代码中如下语句:
     是使用串口1,于是把开发板上的USART1插上USB转串口模块。准备下载后调试。
     
        插上模块后开始下载,结果发现不能下载,报错信息如下图所示:
         猜测可能是串口模块干扰到SWD下载,于是把串口模块拔掉。结果发现开发板没电了。
    也就是说,刚刚是靠串口模块供电的。即刚刚也可能是MCU供电不足导致无法下载。于是
    先拨动开关,用外接电源给开发板供电,

        然后再重新烧录,结果一次就成功了。
        下面先把USB转串口模块插回开发板的USART1,测试串口功能是否正常。
    打开串口调试工具,选择串口后,点击“打开串口”,串口调试助手就开始接受数据了。
        也就是说,正点原子的stm32f1串口代码只要在Keil中修改MCU和flash大小后,可以在微雪
    开发板上直接使用。
        接下来就要准备开始USB相关的工程了。
    《第1部分:参照“正点原子USB虚拟串口工程移植步骤”移植ST的USB HID工程(失败了)
        这里准备大致分为四布调试:
        第一步:了解正点原子的USB虚拟串口实现步骤(不需要记得,大致看一下,需要时再
    回头仔细看);
        第二步:下载正点原子的USB虚拟串口代码到微雪开发板,看是否能正常工作。如果能
    正常工作,则可以轻松地执行第三步;否则需要先查找原因,直到可以正常工作时,再执
    行第三步;
        第三步:不管第二部分是否正常工作,都需要亲自按照第一步的步骤重新移植一遍,为
    移植HID做准备;
        第四步:参照第三步的步骤,移植ST官方库中的HID代码到微雪开发板。
    ---------------  第一步:  (不想看可以先跳过去,直接看第二步)----------
        正点原子视频教程中USB虚拟串口实现步骤如下:
        正点原子f1开发板中USB硬件用的是PA11和PA12。微雪电子开发板中用的也是PA11
    和PA12。查看f103收据手册发现,这款MCU就只有这一个USB接口,所以不用担心搞错
    接口了。正点原子和微雪开发板上都是在USB_D+上接1.5k上拉电阻,说明都定义此USB
    是高速设备。
        下面是《第88讲 USB虚拟串口试验-M3》PPT中移植ST官方的Virtual_COM_Port例程的过程:
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    《stm32f1开发指南-库函数版本》中USB虚拟串口的实现步骤如下:
     
     
     
     
     
     
         
      
     
     
     
     
     
     
     
     
     
    ---------------  第一步结束------------------------------------------------------------------------
    ---------------  第二步: ---------------------------------------------------------------------------
         好了,下面是第二部分,直接下载正点原子开发板的程序,看是否能正常用,如果能
    正常工作,则可以放心的执行第三步;否则,需要先查找到原因后再执行第三步。
     
         为了避免液晶和串口功能的干扰,我们先屏蔽掉代码中的液晶和串口部分的功能。
        下载后实现效果如下:
     
        很幸运,微雪开发板可以直接实现虚拟串口功能,可以直接进入第三步了。
    (注:代码见附件:第二步:实验48 USB虚拟串口实验 _微雪开发板)
    ---------------  步结束---------------------------------------------------------------------------
    ---------------  第三步: -----------------------------------------------------------------------------
    亲自按照第一步的步骤重新移植一遍虚拟串口的代码
    移植后编译,结果报错如下
        在第二步和第三步中的程序中分别查找“ EXTI_ClearITPendingBit”和“EXTI_Init”两个变量。
    第二步程序中搜索结果:

    第三步程序中搜索结果:
    从上面结果看,第三步中工程缺少库文件:stm32f10x_exti.c。于是在Keil中把这个文件包含进去,
    重新编译,结果如下:
    把代码下载到微雪电子开发板中,希望能直接成功。
    结果如下:
    看来电脑识别到USB虚拟串口了。
    (注:代码见附件:第三步:实验4 串口实验 _修改为VCP.rar)
    ---------------  第三步结束---------------------------------------------------------------------
    ---------------  第四--------------------------------------------------------------------------- 
    移植Custom_HID代码到正点原子的串口代码中,希望一切顺利。
    参照PPT《第88讲 USB虚拟串口实验-M3》,开始进行下列移植:
    1.打开ST官方的Custom_HID例程,如下图所示
     
    2.移植USB通信需要的从机驱动代码;
    3.打开USUART通信实验,拷贝USB从机驱动代码;
     4.打开 USART试验工程,添加USB相关代码,如下图所示:
    突然发现PPT中有下列一句话:
            原来第三步中刚开始调试报错,是因为没看到这里的"添加stm32f10x_exti.c"。
    还是太粗心了。
    5.编译代码,根据报错提示,修改相关内容。
    ①, platform_config.h, include部分, 使用如下代码替代:
    #include "sys.h"
     
    另外, 去掉#define USE_STM32303C_EVAL等宏定义, 无需使用
    ②,修改hw_config.c。
    2.1,去掉stm32_it.h,并添加一些其他头文件,如下:
    #include "usb_lib.h"
    #include "usb_prop.h"
    #include "usb_desc.h"
    #include "usb_istr.h"
    #include "hw_config.h"
    #include "usb_pwr.h"
    #include "usart.h"
    #include "string.h"
    #include "stdarg.h"
    #include "stdio.h" 
     
        因为HID例程中此处没有stm32_it.h,所以直接替换成上面的代码。
    2.2,去掉HSEStartUpStatus和EXTI_InitStructure等结构体和变量的定义,
    , 采用如下代码替代  :
        因为替换的代码是串口相关的,所以此时不知道是否应该替换了!!!
    那就先编译一下,根据报错提示修改看看是否能直接运行。
    编译结果如下:
        发现有很多错误,是跟评估板硬件相关的内容,应该是哪个宏定义没正确使用。
    这样一个一个修改太麻烦了,还是先根据PPT《第88讲 USB虚拟串口实验-M3》,
    接着把" 能修改的部分 "修改了再根据情况调试。注:2.2这节暂时不修改了。
    2.3,删掉Set_System函数并添加USBWakeUp_IRQHandler和USB_LP_
    CAN1_RX0_IRQHandler函数(官方例程是在stm32_it.c里面, 我们将其移到
    这里) , 代码如下
    //USB唤醒中断服务函数
    void USBWakeUp_IRQHandler(void)
    {
        EXTI_ClearITPendingBit(EXTI_Line18);//清除USB唤醒中断挂起位
    }
    //USB中断处理函数
    void USB_LP_CAN1_RX0_IRQHandler(void)
    {
        USB_Istr();
    } 
     
    2.4,修改Set_USBClock函数为:
    2.5,修改Enter_LowPowerMode函数为:
    2.6,修改Leave_LowPowerMode函数为:
    2.7,修改USB_Interrupts_Config函数为:
    2.8,修改USB_Cable_Config函数为:
    2.9,删除USART_Config_Default函数,新增USB_Port_Set函数,代码如下:
    因为当前例程中没有虚拟串口,所以不用删除,直接添加USB_Port_Set函数即可。
    2.10,修改USART_Config函数为:(和串口相关,不用管):
    2.11,修改USB_To_USART_Send_Data函数为(和串口相关,不用管):
    2.12,删除Handle_USBAsynchXfer和USART_To_USB_Send_Data这两个
    函数, 然后, 新增USB_USART_SendData函数, 用于虚拟串口发送一个字节
    到USB(这里实际上只写到了发送FIFO, 最终还是由EP1_IN_Callback函数实
    现输出给USB):(和串口相关,不用管):
    2.13, 删除IntToUnicode函数前面的static关键字, 
    新增usb_printf函数, 用于实现USB虚拟串口的printf, 代码如下: (和串口相关,不用管):
    2.14, 修改hw_config.h, 删除MASS_MEMORY_START等宏定义, 然后, 新
    增USB_USART_TXFIFO_SIZE等宏定义和结构体, 代码如下: (和串口相关,不用管):
    2.15, 修改hw_config.h, 新增IntToUnicode、USB_Port_Set 
    USB_USART_SendData、和usb_printf等函数的声明, 代码如下: (和串口相关,不用管):
    ④, 修改usb_endp.c。 
    4.1, 修改EP1_IN_Callback函数为: (和串口相关,不用管):
    4.2, 修改SOF_Callback函数为:(工程中没有这个函数的定义,直接从虚拟串口的工程中复制过来):
    ⑤, 修改usb_prop.c。 本例程没有用到USART_Config_Default函数, 所以:
    注释掉Virtual_Com_Port_init函数里面对该函数的调用:(工程中没有这个函数,不用管):
    ⑥, 修改usb_pwr.c。 修改Suspend函数为:
    6, 修改main.c。
    因为虚拟串口例程中的main.c里面执行的是串口收发,所以这里只用其初始化部分,while(1)
    里面什么也不做。结果编译后报错如下:
         还是很多宏定义没有实现。接下来需要找到他们,定义他们或者删除他们。
    第一个报错:RCC_APB2Periph_GPIO_DISCONNECT未定义。定位到函数如下:
    void GPIO_Configuration(void)
     
        但是程序中并未调用它,所以可以直接屏蔽掉。
    重新编译后,第一个报错:KEY_BUTTON_EXTI_LINE未定义。定位到函数如下:
    void EXTI_Configuration(void)
     
        但是程序中并未调用它,所以可以直接屏蔽掉。
    重新编译后,第一个报错:ADC1_DR_Address未定义。定位到函数如下:
    void ADC_Configuration(void)
     
        但是程序中并未调用它,所以可以直接屏蔽掉。
    重新编译后,第一个报错:LED1未定义。定位到函数如下:
    void EP1_OUT_Callback(void)
     
     
        该函数的功能是接收从PC端发过来的数据。不能屏蔽掉。因为函数内容可以
    自定义,于是把里面原来开发板上的功能(主要是开关LED)屏蔽掉。只接收数据,
    不做处理。
        重新编译后,第一个报错:LED1未定义。定位到函数如下:
    第一个报错:还是LED1未定义。定位到函数如下:
    void CustomHID_Status_In(void)
     
        该函数的功能是:状态输入。虽然不知道具体是做什么的,但是根据网上看过
    的HID程序资料,这个函数不能删除。于是只屏蔽掉里面关于LED等信息的语句。
        重新编译后,只有3个错误了:

    第一个报错:
    bDeviceState未定义。定位到函数如下: 
    void SOF_Callback(void)
     
     
        关于这个函数,网上找到下列解释:
        函数SOF_Callback定时查询用户是否有要发送的数据,如果有则进行发送,
    发送完成后会触发发送中断EP1_IN_Callback函数,如果发送完毕就不调用
    SetEPTxValid(ENDP1)函数,发送完成后就不会再触发EP1_IN_Callback函数。
        所以就不删除了。bDeviceState在代码中肯定是定义过了的,应该是被屏蔽了。
     搜索变量bDeviceState,看它的定义在什么地方,为什么被屏蔽了。结果如下:
         看来确实定义过,还在头文件中声明过可以外部调用。那应该是这个头文件
    没有被usb_endp.c包含导致的。打开usb_endp.c查看,果然没有这个头文件。
    加上后,编译结果如下:
         很多关于usb_prop.h的错误,这个是才加进去的头文件,却导致个能多错误,
    应该是加的位置不对。打开看到usb_endp.c开头只有几个头文件:
    #include "hw_config.h"
    #include "usb_lib.h"
    #include "usb_istr.h"
    #include "usb_prop.h"
     
     
    干脆直接把USB虚拟串口相同文件中包含的头文件都包含进来编译看看。结果如下:
        老规矩,全局搜索变量“VCOMPORT_IN_FRAME_INTERVAL”,结果如下: 
         竟然发现代码中真的没有定义过。因为这个代码是从USB虚拟串口拷贝过来的,在
    USB虚拟串口代码中全局搜索,结果如下:
         直接在usb_endp.c开头加上这个宏定义,重新编译结果如下:
        直接点击错误信息,不能跳转,全局搜索PrevXferComplete,结果如下:
         发现竟然真的没有定义。这部分是ST官方库中的代码,直接打开ST的HID工程,
    全局搜索,发现是在main.c开始位置定义的。于是我们也在main.c处定义这个变量,
    编译后结果如下:
         ADC_SoftwareStartConvCmd好像是和串口有关,但没有直接证据,全局搜索发现
        也就是说,这个函数只有声明,没有定义。
        同理,在ST官方库中HID工程中搜索,结果如下:
         原来,这个函数在adc库文件中。而我的工程还没有添加这个库文件。
         添加后编译,结果如下:
        没有报错,很好,但是下载后结果如何还不知道,因为刚刚在ST的HID工程中看到main函数
    初始化时的步骤和这里从USB虚拟串口移植过来的不一样。不过还是先试一下看看。
        开始下载......
        微雪开发板上电后结果如下:
         太神奇了,虽然初始化代码和ST工程不一样,但竟然一下子就识别成HID了!!!
       
         趁热打铁,接下来就是实现HID发送和接收功能,否则小孙的三分钟热性一旦消失,就要再
    耗费半天才能继续下去了。
        刚才细看USB虚拟串口代码,发现其发送和接收功能其实和网上的HID类似,都是调用
    UserToPMABufferCopy()和PMAToUserBufferCopy()函数。而这两个函数分别有另一个函
    数调用,即USB_SIL_Write()和USB_SIL_Read()。在ST的HID工程中也有这两个函数,这
    里先实现他们看看是否有效果。
     
         添加上面的代码,编译下载后结果如下:
         一直没有数据发送上来。看来需要让开发板在调试模式运行,看是否是卡在哪里了。
    结果调试模式下发现,代码一直在循环执行,没有卡顿问题。就是说,发送代码执行了,
    但是数据没有发送出去。
        打开USB的配置描述符发现,默认最大发送长度为2字节,而小孙的发送函数一次发送
    3字节,需要修改一下。
        修改之后,编译下载,结果还是和上面一样,不能发送数据。
        把单片机多功能调试助手打开,打开开发板的端口检测。结果仍然没有数据发送。
        把串口初始化代码屏蔽掉时,PC端反而不能识别HID了。
        分析uart_init()函数,没发现什么特别功能的语句。屏蔽掉它,继续调试。
    但是目前进度卡住了,不知道怎么向下调试了。
        这种情况,一年前刚刚学习stm32 USB时就遇到过,后来是别人替小孙调好的。
    当时小孙调了接近1个月,都没有正常收发数据,后来觉得自己短时间内调不出来
    了跟领导说让其重新招人,自己准备辞职的。后来是领导花两三天帮他调试出来的。
        虽然当时已经有两年半工作经验了,但那几天都在想自己是否真的适合走嵌入式这条路???
        因为没有刨根问底的精神,小孙这几年的电子生涯一直是闭着眼睛瞎混的,没有
    好好的钻研让自己拿得出手的技术,所以每天都生活在自卑和失落中。
        综上所述,在屏蔽掉uart_init()函数后,程序并不能被PC识别为HID设备。
    《第2部分:在1的基础上,替换USB HID初始化代码为ST 例程中的代码,编译后根据报错调试(失败了)》
        俗话说,人不能让不撞南墙不回头,这里是装了南墙必须回头,否则没有哪个
    老板愿意给你薪水。所以,小孙准备从ST的HID工程本身提供的初始化HID方式
    尝试实现HID功能。毕竟,网上大多数HID工程初始化部分都和ST的HID部分类似,
    而跟他上面自己移植的不一样。
    ******************  根据ST的HID修改工程代码 ***********************
    预想中的修改步骤如下:
    第一步:先用HID工程中的初始化代码替换上面工程中的初始化代码;
    第二步:根据报错,修改上面步骤中被修改过的相关函数,使HID初始化成功;
    第三步:添加HID发送和接收函数,并实现功能;
    ---------------  第一步: -----------------------------------------------------------------------------
        移植ST的HID工程初始化代码后编译,结果如下:
         发现报错中提到的函数是上面在hw_config.c中屏蔽掉的,于是释放开。重新编译后
    报错如下:
         发现其中大都是跟具体硬件相关的。
        全局搜索第一处的未定义变量,发现在platform_config.h中有两处根据开发板
    类型分别定义的变量。
        在STM3210E_EVAL开发板原理图上发现,上面的GPIO_DISCONNECT是
    指接在USBDP上的上拉电阻控制线。
        因为微雪电子开发板上USBPD上的上拉电阻通过三极管直接拉高了,所以这里
    不用管,直接屏蔽掉。还有下面的配置USB_DISCONNECT_PIN的
    GPIO_Configuration函数也一起屏蔽掉,再编译,结果如下:
        
         全局搜索“RCC_AHBPeriph_GPIOA”,结果如下:
         并没有找到其定义,在ST的HID官方库中搜索结果如下:
         即,其定义在stm32f30x_rcc.h中,文件对应MCU型号不对。在stm32f10x_rcc.h中
    搜索GPIOA的时钟外设对应的变量,有如下发现:
         用RCC_APB2Periph_GPIOA替代上面的RCC_AHBPeriph_GPIOA,重新编译结果如下:
         下载后,PC端显示如下:
         调到这一步,小孙已经失去耐心了,不愿意在USB HID的工程上花时间调试了。因为网上的HID
    都是从stm32手柄工程修改过来的,准备第二天换成JoyStickMouse工程,从上面开始调试。
        ------------------------------------------------------     两天后   ------------------------------------------------------------
     
    《第3部分:直接移植ST的USB HID工程,根据报错调试代码(成功了)》
         小孙经过重新思考,准备重新从ST的HID库直接修改,而不是先参考正点原子USB虚拟串口,把里面
    的相关函数修改了。如果还是不成功,再参考网上从“ JoyStickMouse”修改。
     
        把ST的HID代码添加到正点原子的串口实验代码中,修改main.c中初始化语句为ST的HID代码,
    屏蔽掉原串口代码并编译。结果如下:
         缺少对开发板的宏定义,这里直接用“#include "stm32f10x.h"”替换。编译结果如下:
        “usb_type.h”在移植过来的USB库中,直接用"
    #include "../STM32_USB-FS-Device_Driver/inc/usb_type.h" "包含进来。
        重新编译后结果为:
         仿照上面操作,添加把“usb_lib.h”包含进来,重新编译后结果为:
         还有下列文件需要包含这些头文件,一并处理了。
        stm32_it.c,hw_config.c,usb_desc.c,usb_pwr.c,usb_endp.c,usb_prop.c
    还有STM32_USB-FS-Device_Devicesrusb_core.c,usb_init.c,usb_int.c,
    usb_regs.c,usb_mem.c,usb_sil.c需要用“../inc/usb_lib.h”包含“usb_lib.h”文件。
        编译后报错:
         说明上面添加的头文件正确。接下来需要屏蔽掉与具体硬件相关的代码。定位到
    “KEY_BUTTON_EXTI_LINE”,如下:
         这个是开发板的按键中断处理函数,直接屏蔽掉。
        重新编译,报错如下:
         第一个报错:RCC_APB2Periph_GPIO_DISCONNECT在上面看过了,是
    USBDP的上拉电阻,微雪开发板不需要上拉电阻,是直接拉高的,屏蔽掉。
    还有,stm32f103的usb管脚不需要配置,当设置好usb时钟后,直接就用作usb功能了。
    Set_System函数中把他们屏蔽掉,还有按键,led,adc功能都屏蔽掉。
    这样,Set_System()函数的内容都屏蔽掉了。
        重新编译,报错如下:
         第一个报错“STM_EVAL_LEDOn”在函数CustomHID_Status_In()"中,其功能是
    控制LED的,直接屏蔽掉内容,保留外壳。
        重新编译,报错如下:
         根据上面信息,这里直接屏蔽GPIO相关的函数内容,保留外壳,重新编译报错信息如下:
         还是按键灯功能,直接屏蔽函数内容,保留外壳。
        重新编译,报错如下:
     
        屏蔽掉部分函数体,保留外壳及部分功能,因为这个函数中需要把PC发来的数据接收下来,
    以后才能继续接收数据。
     
         编译结果如下:
         移植来的stm32_it.c里面有很多中断处理函数和stm32f10x_it.c重复,直接屏蔽掉重复部分。
    重新编译,报错信息如下:
         主要是hw_config.c、stm32_it.c,和usb_prop.cADC和DMA功能,直接屏蔽掉。
    至于EXTI_ClearITPendingBit,如下所示,屏蔽掉宏定义的限制。
       
        至于保留哪一个函数名,直接分别全局搜索他们,发现stm32f10x对应的是下面的函数名。
       屏蔽后重新编译,报错如下:
        全局搜索如下:     
         看来工程中缺少包含stm32f10x_exti.c,包含后重新编译,报错信息如下:
        全局搜索如下:   
        未找到定义,在ST的HID工程中查找结果如下:
         在main.c中找到了。添加到自己的工程中后,编译结果如下:
         终于把所有的错误调好了。下载看看是否识别到HID。
     
         发现还是不能识别HID,看来usb初始化代码有问题。下面从头开始查看初始化代码。
        
         第一个“Set_System()”,根据上面结论,不用管;
        第二个“USB_Interrupts_Config()”如下:
       
        根据需要屏蔽上面的不相干代码,结果如下所示:
        重新编译下载,结果如下
     
        添加发送函数,如下:
        下载结果如下:
     
         屏蔽掉发送函数后,重新编译下载,还是失败。
    修改VID后,重新下载,还是失败。
        
     重新按照上面的步骤生成新的工程,依然是“未知USB设备”,请求设备描述符失败。
        此后觉得自己永远没法独立调试出来了,然后用BeyondCompare软件比较上面
    的最后一版软件和别人帮我调试好的代码,还有微雪开发板的USB手柄代码,不断
    地屏蔽、复制和粘贴,以排除。最后发现是Suspend()函数被修改成了下面的样子,
    才会让代码从不能用变为能用。
         此时,下载结果如下:
        后来发现,在正点原子的USB虚拟串口实验中,Suspend()函数也是被修改成上面的样子的!!!
       **********************************************************************************************************************
        下面开始进行HID数据的发送!
        在usb_sil.c中发现一个USB发送函数“USB_SIL_Write”,将其放到while(1)中,如下所示:
         编译后下载,结果如下:
         没有数据输出。
        在网上找到发送函数的用法发现:
         于是增加语句:SetEPRxValid(ENDP1),编译下载后,还是没有数据发送。
    在上面的USB虚拟串口代码中查找发送代码,发现发送函数USB_SIL_Write()并没有被调用,
    而是使用下列语句发送的:
        而USB_SIL_Write()函数如下:
         上面函数的前两行和USB虚拟串口调用的发送代码相同,但是USB虚拟串口还是用了
    SetEPTxValid()函数,这和上面从网上找到的SetEPRxValid()函数不同。尝试替换,看是
    否能发送数据
     
         结果如下:BusHound报错如下:
         从网上搜到:
         于是分别修改下列几处代码:
    (1) usb_desc.c中:
     (2)usb_prop.c中:
     (3)stm32f10x_it.c中:
        没找到相关信息,暂时不改。
     (4)在usb_desc.c中:
     (5)usb_desc.h中:
         重新编译后,下载,结果如下:
     USB数据发送完成!
     下面开始进行HID数据的接收!
        在usb_endp.c中有接收数据,用于控制LED。  
     
         在keil的调试模式下,用BusHound发送数据
     
         在Keil中的Watch1窗口中观察变量:Receive_Buffer,结果发现数据并未变化。
        
         本以为HID接收功能失败了,结果在点击调试暂停按钮时意外发现数据收到了:
     
        看来,数据确实收到了,只是暂时未显示出来。
    那么,先判断收到的数据,再把数据返回,以此来判断数据收发是否正常。
    看起效果如下:
         所以,上面的数据收发功能正常。(代码见附件:第5步:实验4 串口实验 从头开始修改为HID_20170801_5.rar)
  • 相关阅读:
    Scalaz(15)- Monad:依赖注入-Reader besides Cake
    Scalaz(14)- Monad:函数组合-Kleisli to Reader
    Scalaz(13)- Monad:Writer
    Scalaz(12)- Monad:再述述flatMap,顺便了解MonadPlus
    Scalaz(11)- Monad:你存在的意义
    Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern
    Scalaz(9)- typeclass:checking instance abiding the laws
    Scalaz(8)- typeclass:Monoid and Foldable
    Scalaz(7)- typeclass:Applicative-idomatic function application
    Scalaz(6)- typeclass:Functor-just map
  • 原文地址:https://www.cnblogs.com/sz189981/p/7291121.html
Copyright © 2011-2022 走看看