



一句话说明白,
TM7705是一个外置16位分辨率双通道ADC芯片,SPI通信协议,采用Σ-∆转换技术。
价格便宜,对标同型号AD7705,基本能直接替换,程序基本通用。
AD7705是美国模拟器件公司生产的。15元左右。
TM7705 是深圳天微生产的,引脚和功能和AD7705完全兼容。可以替代AD7705。价格比进口的便宜几倍。5元左右。
(1)TM7705多一个内部2.48V参考电压,可以通过写测试寄存器开启(默认不开启)
(2)TM7705多一种时钟设置方法,可以提高精度。时钟寄存器的ZERO 3个bit位中最高位=1来启用。这种模式下,数据刷新率变低(每秒10个样本),精度变高。

在CSDN上,搜索TM7705
这两篇文章是讲解的比较详细的,
STM32F103ZET6驱动TM7705(AD7705)代码加心得
http://t.csdn.cn/lWMiE
不过,都没有解决一个实际性的问题,怎么用起来 这个adc


下载收费积分都是次要的。
最重要的一点是,代码问题重重。
经常TIME OUT ,超时
初始化,以及获取一次ADC需要大概10秒。
似乎是偶尔运行成功一样。
程序是存在问题的。

和作者评论区讨论未果,也许年代久远,作者也难在实际调试

此代码实际运行视频我会放在文末链接中。
驱动原理讲解确实很详细,建议学习时,仔细阅读。点赞
却只给出了C,H文件,
加入工程并不难,不过,代码简单明了,适合老手进阶使用。
缺乏通用性,代码编程风格相比于前一个文章以及安富莱电子得代码来说,规范性上差太多了。
另外,每次获取值,都要初始化一次。似乎存在重复操作。



总之,在CSDN上,代码存在超时问题,一直未得到解决,
adc数据可以获取到,但是TM7705模块DRDY电平一直为高的问题,始终存在。
经过对数据手册的仔细阅读,程序大体流程如下:

大概可以理解成分布式的寄存器结构。
通信寄存器就是那个大哥,你要动他哪个小弟,怎么动,你都得先告诉他,有的小弟打完了还要告诉大哥结果怎们样。

不多废话了。直接上代码。

优化后,是网上代码-STM32F103ZET6驱动TM7705(AD7705)代码加心得代码修改而来。采用硬件SPI.
另外,自己也写了一个适合更改单片机引脚的软件SPI程序。
百度云
https://pan.baidu.com/s/1W1pj8wGVMaSwfc3mdO-0ZQ?pwd=6666
链接:https://pan.baidu.com/s/1W1pj8wGVMaSwfc3mdO-0ZQ?pwd=6666
提取码:6666

MAIN.C
#include <delay.h>
#include <sys.h>
#include <usart.h>
#include <lcd.h>
#include <drv_spi.h>
#include <drv_tm7705.h>
char BUFFER[200];
int main(void)
{
int volt1,volt2;
uint16_t adc1,adc2;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVUC中断分组为2
uart_init(115200);
delay_init();
LCD_Init();
POINT_COLOR = RED;
TM7705_Init();
TM7705_CalibSelf(1); //自校准
adc1 = TM7705_ReadAdc(1);
TM7705_CalibSelf(2); //自校准
adc2 = TM7705_ReadAdc(2);
while(1)
{
adc1 = TM7705_ReadAdc(1);
adc2 = TM7705_ReadAdc(2);
volt1 = (adc1 * 5000) / 65535;
volt2 = (adc2 * 5000) / 65535;
sprintf(BUFFER,"CH1=%5d v1:%5dmv",adc1,volt1);
printf("CH1=%5d v1:%5dmv\r\n",adc1,volt1);
LCD_ShowString(60,154,200,16,16,BUFFER);
sprintf(BUFFER,"CH2=%5d v2:%5dmv",adc2,volt2);
printf("CH2=%5d v2:%5dmv\r\n",adc2,volt2);
LCD_ShowString(60,170,200,16,16,BUFFER);
}
}
#include <drv_tm7705.h>
#include <drv_spi.h>
#include <delay.h>
#include <lcd.h>
/*
TM7705模块可以直接插到STM32f103战舰开发板模块的排母接口上。
TM7705模块 STM32F103正点原子战舰开发板
SCK ------ PB13/SPI2_SCK
DOUT ------ PB14/SPI2_MISO
DIN ------ PB15/SPI3_MOSI
CS ------ PG7/NRF24L01_CS
DRDY ------ PG8/NRF24L01_IRQ
RST ------ PG6/NRF_CE
*/
#define TM7705_CS PGout(7) //CS片选宏定义,低电平有效
#define TM7705_RST PGout(6) //RST使能复位宏定义,低电平有效
#define TM7705_DRDY PGin(8) //DRDY,低电平时表示TM7705可读
/*================下面为芯片的驱动数据定义============================*/
/* 通信寄存器bit定义 */
enum
{
/* 寄存器选择 RS2 RS1 RS0 */
REG_COMM = 0x00, /* 通信寄存器 */
REG_SETUP = 0x10, /* 设置寄存器 */
REG_CLOCK = 0x20, /* 时钟寄存器 */
REG_DATA = 0x30, /* 数据寄存器 */
REG_ZERO_CH1 = 0x60, /* CH1 偏移寄存器 */
REG_FULL_CH1 = 0x70, /* CH1 满量程寄存器 */
REG_ZERO_CH2 = 0x61, /* CH2 偏移寄存器 */
REG_FULL_CH2 = 0x71, /* CH2 满量程寄存器 */
/* 读写操作 */
WRITE = 0x00, /* 写操作 */
READ = 0x08, /* 读操作 */
/* 通道 */
CH_1 = 0, /* AIN1+ AIN1- */
CH_2 = 1, /* AIN2+ AIN2- */
CH_3 = 2, /* AIN1- AIN1- */
CH_4 = 3 /* AIN1- AIN2- */
};
/* 设置寄存器bit定义 */
enum
{
MD_NORMAL = (0 << 6), /* 正常模式 */
MD_CAL_SELF = (1 << 6), /* 自校准模式 */
MD_CAL_ZERO = (2 << 6), /* 校准0刻度模式 */
MD_CAL_FULL = (3 << 6), /* 校准满刻度模式 */
GAIN_1 = (0 << 3), /* 增益 */
GAIN_2 = (1 << 3), /* 增益 */
GAIN_4 = (2 << 3), /* 增益 */
GAIN_8 = (3 << 3), /* 增益 */
GAIN_16 = (4 << 3), /* 增益 */
GAIN_32 = (5 << 3), /* 增益 */
GAIN_64 = (6 << 3), /* 增益 */
GAIN_128 = (7 << 3), /* 增益 */
/* 无论双极性还是单极性都不改变任何输入信号的状态,它只改变输出数据的代码和转换函数上的校准点 */
BIPOLAR = (0 << 2), /* 双极性输入 */
UNIPOLAR = (1 << 2), /* 单极性输入 */
BUF_NO = (0 << 1), /* 输入无缓冲(内部缓冲器不启用) */
BUF_EN = (1 << 1), /* 输入有缓冲 (启用内部缓冲器) 可处理高阻抗源 */
FSYNC_0 = 0,
FSYNC_1 = 1 /* 不启用 */
};
/* 时钟寄存器bit定义 */
enum
{
CLKDIS_0 = 0x00, /* 时钟输出使能 (当外接晶振时,必须使能才能振荡) */
CLKDIS_1 = 0x10, /* 时钟禁止 (当外部提供时钟时,设置该位可以禁止MCK_OUT引脚输出时钟以省电 */
CLK_4_9152M = 0x08,
CLK_2_4576M = 0x00,
CLK_1M = 0x04,
CLK_2M = 0x0C,
/*输出更新速率设置*/
FS_20HZ = 0X00,
FS_25HZ = 0x01,
FS_100HZ = 0x20,
FS_200HZ = 0x03,
FS_50HZ = 0x04,
FS_60HZ = 0x05,
FS_250HZ = 0x06,
FS_500HZ = 0x07,
ZERO_0 = 0x00,
ZERO_1 = 0x80
};
static void TM7705_ResetHard(void); //硬件复位
static void TM7705_SyncSPI(void);
static uint16_t TM7705_Read2Byte(void);
/*====================芯片的驱动数据定义到此结束==========================*/
void TM7705_Init(void) //初始化函数
{
uint16_t read = 0;
/*==信号引脚初始化==*/
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOG, ENABLE); //使能PB,G端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PB12上拉 防止W25X的干扰
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化指定IO
GPIO_SetBits(GPIOB,GPIO_Pin_12);//上拉
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //PG 7 推挽 CS
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化指定IO
GPIO_SetBits(GPIOG,GPIO_Pin_7);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //PG6 推挽 RST
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化指定IO
GPIO_ResetBits(GPIOG,GPIO_Pin_6 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PG8 输入 DRAY
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_ResetBits(GPIOG,GPIO_Pin_8 );
SPI2_Init(); //初始化SPI2外设,在drv_spi.h中实现
SPI2_SetSpeed(SPI_BaudRatePrescaler_4);//设置为时钟
TM7705_CS = 1; //TM7705初始化不选中
TM7705_ResetHard(); //硬件复位
TM7705_SyncSPI(); //同步SPI接口时序
/*配置时钟寄存器*/
TM7705_CS = 0;
SPI2_ReadWriteByte(REG_CLOCK | WRITE |CH_1); //先写通信寄存器,下一步写时钟寄存器
SPI2_ReadWriteByte(CLKDIS_0 | CLK_4_9152M | FS_50HZ ); //刷新速率250HZ
SPI2_ReadWriteByte(REG_CLOCK | WRITE |CH_2); //先写通信寄存器,下一步写时钟寄存器
SPI2_ReadWriteByte(CLKDIS_0 | CLK_4_9152M | FS_50HZ ); //刷新速率250HZ
TM7705_CS = 1;
SPI2_ReadWriteByte(REG_SETUP | WRITE |CH_1); //先写通信寄存器,下一步写设置寄存器
SPI2_ReadWriteByte(MD_NORMAL | GAIN_1 | UNIPOLAR |BUF_EN |FSYNC_0 ); //写设置寄存器正常模式,增益为1、dan极性、有缓冲、滤波器工作、
/*每次上电进行一次自校准*/
TM7705_CalibSelf(1); //内部自校准
SPI2_ReadWriteByte(REG_SETUP | WRITE |CH_2); //先写通信寄存器,下一步写设置寄存器
SPI2_ReadWriteByte(MD_NORMAL | GAIN_1 | UNIPOLAR |BUF_EN |FSYNC_0 ); //写设置寄存器正常模式,增益为1、dan极性、有缓冲、滤波器工作、
TM7705_CalibSelf(2); //内部自校准
// SPI2_ReadWriteByte(0x39);
// read = TM7705_Read2Byte();
}
/*===硬件复位Tm7705芯片,无出入参数===*/
static void TM7705_ResetHard(void) //硬件复位
{
TM7705_RST = 1;
delay_ms(1);
TM7705_RST = 0;
delay_ms(20);
TM7705_RST = 1;
delay_ms(1);
}
/*=============================================
= 功能:同步TM7705芯片SPI接口时序
= 说明:连续发送32个1即可,不同步会发生数据错位
==============================================*/
static void TM7705_SyncSPI(void) //同步SPI接口时序
{
TM7705_CS = 0;
SPI2_ReadWriteByte(0xFF);//32个1
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
TM7705_CS = 1;
delay_ms(1);
}
/*====================================================================
=功能说明: 等待内部操作完成,自校准时间较长,需要等待
=参 数: 无
======================================================================*/
static void TM7705_WaitDRDY(void)
{
delay_ms(40);
while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_8==1)){}//待数据准备好AdDrdy=0,0代表数据准备好了。1的时候没准备好,等待
}
/*====================================================================
= 功能说明: 启动自校准. 内部自动短接AIN+ AIN-校准0位,内部短接到Vref
校准满位。此函数执行过程较长,实测约 180ms
= 形 参: _ch : ADC通道,1或2
=====================================================================*/
void TM7705_CalibSelf(uint8_t _ch)
{
if (_ch == 1)
{
/* 自校准CH1 */
SPI2_ReadWriteByte(REG_SETUP | WRITE | CH_1); /* 写通信寄存器,下一步是写设置寄存器,通道1 */
SPI2_ReadWriteByte(MD_CAL_SELF | GAIN_1 | UNIPOLAR |BUF_EN |FSYNC_0);/* 启动自校准 *///写设置寄存器,单极性、有缓冲、增益为1、滤波器工作、自校准
delay_ms(190);
TM7705_WaitDRDY(); /* 等待内部操作完成 --- 时间较长,约180ms */
}
else if (_ch == 2)
{
/* 自校准CH2 */
SPI2_ReadWriteByte(REG_SETUP | WRITE | CH_2); /* 写通信寄存器,下一步是写设置寄存器,通道2 */
SPI2_ReadWriteByte(MD_CAL_SELF | GAIN_1 | UNIPOLAR |BUF_EN |FSYNC_0); /* 启动自校准 */
delay_ms(190);
TM7705_WaitDRDY(); /* 等待内部操作完成 --- 时间较长,约180ms */
}
}
/*=====================================================================
=功能说明:读到一个8位数据
=参 数:返回读到的值
=====================================================================*/
static uint8_t TM7705_ReadByte(void)
{
uint8_t read = 0;
TM7705_CS = 0;
read = SPI2_ReadWriteByte(0xFF);
TM7705_CS = 1;
return read;
}
/*=====================================================================
=功能说明:读到一个16位数据(半字)
=参 数:返回读到16位数据的值
=====================================================================*/
static uint16_t TM7705_Read2Byte()
{
uint16_t read = 0;
TM7705_CS =0 ;
read = SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
TM7705_CS =1 ;
return read;
}
/*=====================================================================
=功能说明:读到一个24位数据(3字节)
=参 数:返回读到24位数据的值
=====================================================================*/
static uint16_t TM7705_Read3Byte(void)
{
uint32_t read = 0;
TM7705_CS = 0;
read = SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
read <<=8;
read += SPI2_ReadWriteByte(0xFF);
TM7705_CS =1 ;
return read;
}
/*=====================================================================
=功能说明:读取采样电压值
=参 数:返回采样值
=====================================================================*/
uint16_t TM7705_ReadAdc(uint8_t _ch)
{
uint8_t i;
uint16_t read = 0;
/* 为了避免通道切换造成读数失效,读2次 */
for (i = 0; i < 2; i++)
{
TM7705_WaitDRDY(); /* 等待DRDY口线为0 */
if (_ch == 1)
{
SPI2_ReadWriteByte(0x38);
}
else if (_ch == 2)
{
SPI2_ReadWriteByte(0x39);
}
read = TM7705_Read2Byte();
}
return read;
}
#ifndef _DRV_TM7705_H
#define _DRV_TM7705_H
#include "sys.h"
void TM7705_CalibSelf(uint8_t _ch); //启动自校准
void TM7705_Init(void); //初始化函数
uint16_t TM7705_ReadAdc(uint8_t _ch);//读值
#endif
#include "drv_spi.h"
//SPI口初始化
//这里针是对SPI2的初始化
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
SPI2_ReadWriteByte(0xff);//启动传输
}
//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2 2分频
//SPI_BaudRatePrescaler_8 8分频
//SPI_BaudRatePrescaler_16 16分频
//SPI_BaudRatePrescaler_256 256分频
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//检测传递给函数的参数是否是有效的参数
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度
SPI_Cmd(SPI2,ENABLE);
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
#ifndef __DRV_SPI_H
#define __DRV_SPI_H
#include "sys.h"
void SPI2_Init(void); //初始化SPI口
void SPI2_SetSpeed(u8 SpeedSet); //设置SPI速度
u8 SPI2_ReadWriteByte(u8 TxData);//SPI总线读写一个字节
#endif
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
我使用的是最新版本的Chrome(32.0.1700.107)和Chrome驱动程序(V2.8)。但是当我在Ruby中使用以下代码运行示例测试时:require'selenium-webdriver'WAIT=Selenium::WebDriver::Wait.new(timeout:100)$driver=Selenium::WebDriver.for:chrome$driver.manage.window.maximize$driver.navigate.to'https://www.google.co.in'defapps_hoverele_hover=$driver.find_
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易
如果我在功能规范中调用url_for,它会返回一个以http://www.example.com/开头的绝对URL.Capybara会很乐意尝试加载该站点上的页面,但这与我的应用程序无关。以下是重现该问题的最少步骤:从这个Gemfile开始:source'https://rubygems.org'gem"sqlite3"gem"jquery-rails"gem"draper"gem"rails",'4.1.0'gem"therubyracer"gem"uglifier"gem"rspec-rails"gem"capybara"gem"poltergeist"gem"launchy"运行
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的进程隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。MiProcessLoaderEntry(pDriverObject->DriverSection,1)添加MiProcessLoaderEntry(pDriverObject->DriverSection,
我有一个适用于事件/监听器模型的应用程序。发布了几种不同类型的数据(事件),然后许多不同的事情可能需要也可能不需要对该数据(监听器)采取行动。监听器的发生没有特定的顺序,每个监听器将决定是否需要对事件采取行动。Rails应用程序有哪些工具可以完成此任务?我希望自己不必这样做(尽管我可以。这没什么大不了的。)编辑:观察者模式可能是更好的选择 最佳答案 查看EventMachine.它是一个非常流行的Ruby事件处理库。它看起来相当不错,而且很多其他库似乎都在利用它(Cramp)。这是一个很好的介绍:http://rubylearnin
本文代码使用HAL库。文章目录前言一、MCP4017的重要特性二、MCP4017计算RBW阻值三、MCP4017地址四、MCP4017读写函数五、CubeMX创建工程(利用ADC测量MCP4017电压)、对应代码:总结前言一、MCP4017的重要特性蓝桥杯板子上的是MCP4017T-104ELT,如图1。MCP4017是一个可编程电阻,通过写入的数值可以改变电阻的大小。重点在于6引脚(W),5引脚(B