ESP32-硬件SPI读取MCP3208

本文详细介绍了如何使用ESP32通过SPI接口读取MCP3208模拟数字转换器(ADC)的数据。首先,确保SPI连线和驱动正确,然后分析MCP3208的时序图,讲解了如何构造发送和接收的数据包。通过发送特定字节获取12位ADC数据,并提供了相应的读取函数实现。最后,展示了示例代码及其运行效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实驱动也不是针对ESP32,任何芯片去读都可以用下面方法。下面是以esp32为例。

准备条件:

1-确认自己的spi连线没有问题

2-确认自己的spi驱动没有问题

下面先看看MCP3208的手册:

 1-通信速度,先确认自己芯片的最大spi速度。esp32 -spi初始化的时候不要超过这个速度。

2-然后看时序图

2-1 分析一下时序图,

发送:我们发送的第一个字节的1-5bit是我们要关注的,

第一位是开始,没细看,直接写1

第二位是singl/diff,其实就是单边采样和差分采样,我们只看单边的。写1

第3-5位,即D2-D0位就是通道的数据位,根据真值表可以写出第一个字节的值,分别对应8个通道。

uint8_t adc_ch[]={0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8};

 后面3位无意义不关注。后面发送的数据无意义。0xFF即可。

接收:从时序图可以看出,接收的第一个字节有一个B11数据,即adc数据的第12位。

后面的数据则是adc数据的剩下11位。

读取的整体思路

先发送第一个带通道的字节,得到adc的第12位,

然后发送一个0xff,得到11-4位

然后发送一个0xff,得到3-1位。

至此12位数据全部得到,重新组合即可。

编写读取函数:驱动是从之前lcd驱动移植的,会有冗余代码。

#ifndef _MSPI_H_
#define _MSPI_H_

#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define PIN_NUM_MISO 12
#define PIN_NUM_MOSI 13
#define PIN_NUM_CLK  14
#define PIN_NUM_CS   15

#define PIN_NUM_DC   21
#define PIN_NUM_RST  18
#define PIN_NUM_BCKL 5

#define PARALLEL_LINES 16


#define SPI_ADC_CH0 0
#define SPI_ADC_CH1 1
#define SPI_ADC_CH2 2
#define SPI_ADC_CH3 3
#define SPI_ADC_CH4 4
#define SPI_ADC_CH5 5
#define SPI_ADC_CH6 6
#define SPI_ADC_CH7 7


void lcd_spi_pre_transfer_callback(spi_transaction_t *t);
//spi主机初始化
void spi_master_init();
//spi从机初始化
void spi_slave_init();

esp_err_t spi_write( uint8_t *data, int len);
esp_err_t spi_read(uint8_t *data);

esp_err_t spi_read_adc(uint8_t *sdata,uint8_t *rdata);
short spi_read_adc_ch(uint8_t ch);

#endif
#include "driver/gpio.h"
#include "mspi.h"

static spi_device_handle_t spi;
static   spi_bus_config_t buscfg={
        .miso_io_num=PIN_NUM_MISO,
        .mosi_io_num=PIN_NUM_MOSI,
        .sclk_io_num=PIN_NUM_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=1,
    };
static   spi_device_interface_config_t devcfg={
        .clock_speed_hz=100*1000,           //Clock out at 10 MHz
       // .clock_speed_hz=80*1000*1000,
        .mode=0,                                //SPI mode 0
        //.cs_ena_pretrans=1,
        //.cs_ena_posttrans=1,
        .spics_io_num=PIN_NUM_CS,               //CS pin
        .queue_size=5,                          //We want to be able to queue 7 transactions at a time
        //.pre_cb=lcd_spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };

void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
    int dc=(int)t->user;
    //gpio_set_level(PIN_NUM_DC, dc);
}

//spi主机初始化
void spi_master_init()
{

    esp_err_t ret;
    //Initialize the SPI bus
    ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
}
//spi从机初始化
void spi_slave_init()
{
   
}

esp_err_t spi_write(uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t={0};
    if (len==0) return 0;             //no need to send anything
    //memset(&t, 0, sizeof(t));       //Zero out the transaction

    //gpio_set_level(PIN_NUM_CS, 0);

    t.length=len*8;                 //Len is in bytes, transaction length is in bits.
    t.tx_buffer=data;               //Data
    //t.user=(void*)1;                //D/C needs to be set to 1
    ret=spi_device_polling_transmit(spi, &t);  //Transmit!
   
    assert(ret==ESP_OK);            //Should have had no issues.

    //gpio_set_level(PIN_NUM_CS, 1);

    return ret;
}

esp_err_t spi_read(uint8_t *data)
{
    spi_transaction_t t={0};

    //gpio_set_level(PIN_NUM_CS, 0);

    //memset(&t, 0, sizeof(t));
    t.length=8;
    t.flags = SPI_TRANS_USE_RXDATA;
    //t.user = (void*)1;
    esp_err_t ret = spi_device_polling_transmit(spi, &t);
   
    assert( ret == ESP_OK );
    *data = t.rx_data[0];

    //gpio_set_level(PIN_NUM_CS, 1);

    return ret;
}

esp_err_t spi_read_adc(uint8_t *sdata,uint8_t *rdata)
{
    spi_transaction_t t={0};

    //gpio_set_level(PIN_NUM_CS, 0);

    //memset(&t, 0, sizeof(t));
    t.length=8*3
    ;
    t.tx_buffer=sdata;
    t.flags = SPI_TRANS_USE_RXDATA;
    //t.user = (void*)1;
    esp_err_t ret = spi_device_polling_transmit(spi, &t);
   
    assert( ret == ESP_OK );
    rdata[0] = t.rx_data[0];
    rdata[1] = t.rx_data[1];
    rdata[2] = t.rx_data[2];

    //gpio_set_level(PIN_NUM_CS, 1);

    return ret;

}



short spi_read_adc_ch(uint8_t ch)
{
    short ADC_RE;
    uint8_t adc_ch[]={0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8};
    uint8_t spi_sdata1[3]={0xE0,0xff,0xff};
    uint8_t spi_data1[3] ={0};

    spi_sdata1[0]=adc_ch[ch];

    spi_read_adc((uint8_t *)spi_sdata1,(uint8_t *)spi_data1);
    
    
    int v_adc =(spi_data1[0]&0x01)<<11|spi_data1[1]<<3|(spi_data1[2]&0xe0)>>4;

    ADC_RE = v_adc*3300/4095;

    return ADC_RE;
}

 使用:使用spi_read_adc_ch时先初始化spi。

int i_adc =spi_read_adc_ch(SPI_ADC_CH3);
int v_adc =spi_read_adc_ch(SPI_ADC_CH4);
        

printf("esp32-v: %d I:%d, spi-v:%d I:%d\r\n",volt,i_v,v_adc,i_adc);

运行效果:

### ESP32 使用 MCP2515 进行 CAN 通信 #### 硬件连接说明 为了使 ESP32 能够通过 MCP2515 实现 CAN 总线通信,硬件连接至关重要。具体来说,ESP32MCP2515 的 SPI 接口需要正确对接。通常情况下,SPI 数据传输模式被用于两者之间的数据交换。 | ESP32 Pin | Function | Connected to MCP2515 | |-----------|----------------|----------------------| | GND | Ground | GND | | VCC (3V3) | Power Supply | VCC | | GPIO 27 | MOSI | SI | | GPIO 26 | MISO | SO | | GPIO 25 | SCK | SCK | | GPIO 14 | CS | CS/SS | | GPIO 0 | INT | /INT | 以上表格展示了 ESP32MCP2515 之间必要的电气连接[^1]。 #### 示例代码展示 下面提供一段简单的 C++ 代码片段来初始化并配置 ESP32 上的 MCP2515 设备以发送和接收 CAN 帧: ```cpp #include <SPI.h> #include "mcp_can.h" // 定义CS针脚, 对应于MCP2515的片选引脚 #define CAN_CS_PIN 14 MCP_CAN CAN(CAN_CS_PIN); // 创建一个CAN对象实例 void setup() { Serial.begin(115200); while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ)) { Serial.println("CAN BUS Shield init fail"); delay(250); } Serial.println("CAN BUS Shield init OK!"); } void loop() { unsigned char stmp[8]; long id; if (CAN_MSGAVAIL == CAN.checkReceive()) { CAN.readMsgBuf(&id, &stmp); // 获取接收到的消息ID以及数据长度 Serial.print("Received ID="); Serial.println(id); for(int i = 0; i<CAN.getCanMsgLen();i++){ Serial.print(stmp[i], HEX); Serial.print(", "); } Serial.println(); } static int counter = 0; if (++counter % 100 == 0){ byte data[] = {0x0A, 0x0B}; CAN.sendMsgBuf(0x100, 0, sizeof(data), data); } } ``` 这段程序首先设置了串行端口波特率,并尝试启动 CAN 控制器。一旦成功建立连接,则进入无限循环,在其中监听传入的数据帧;当检测到有效消息时读取该消息的内容并向控制台打印出来。此外还包含了每隔一段时间向总线上广播一条测试信息的功能[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值