- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将 STM32 编写为具有简单接口(interface)的 I2C 从设备,其工作原理如下:
所以master每次都会发送一个注册地址,然后从该注册地址写入或读取。
然后从机需要始终接收 1 个字节的注册地址,然后如果下一个操作是读取,则它将该寄存器中的信息发送回主机,或者如果主机的下一个操作是另一个写入,则覆盖该寄存器.
然而,当我运行我的代码时,我得到了一些应该是 ACKS 的 NACKS
这是主请求缓冲区时的响应:在从机完成发送最后一个字节后,您可以在末尾看到 NACK这有点痛苦,但主人收到数据没问题,所以我可以忍受这个
但是,当我尝试写入从属设备上的寄存器时,结果如下:从机接收寄存器地址,然后接收 1 个字节和 ack,然后在接收到第二个字节后由于某种原因它只是保持排队(我需要在这里使用时钟拉伸(stretch))这是不行的,不仅从站没有收到所有数据,而且还锁定了线路以进行任何进一步的通信。为什么我有这个?在这一点上,我为此挠了好几个月 这里的主代码仅供引用(在简单的 Arduino 上运行),因为重点是 STM32 从代码:
#include <Wire.h>
uint16_t read_register(int devAddr, unsigned char regAddr, unsigned char bytes, unsigned char * buffer){
unsigned char i = 0;
Wire.beginTransmission(devAddr);
Wire.write(regAddr);
Wire.endTransmission(false);
Wire.requestFrom(devAddr, bytes , true);
while(Wire.available()){
buffer[i] = Wire.read();
i++;
}
return true;
}
uint16_t write_register(int devAddr, unsigned char regAddr, unsigned char bytes, unsigned char * buffer){
unsigned char i = 0;
Wire.beginTransmission(devAddr);
Wire.write(regAddr); // Reg to write
for(i = 0; i < bytes; i++){
Wire.write(buffer[i]);
}
Wire.endTransmission(true);
return true;
}
void setup()
{
Wire.begin();
Wire.setClock(400);
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("Starting");
}
void loop()
{
unsigned char buffSize = 4;
unsigned char readBuff[buffSize];
unsigned char writeBuff[5] = {0xFB, 0xE3, 0XE2, 0xE1, 0xE0};
for (int i = 0; i < buffSize; i++) readBuff[i] = 0;
read_register(0x1F, 251, buffSize, readBuff);
Serial.print(readBuff[3], HEX);
Serial.print(readBuff[2], HEX);
Serial.print(readBuff[1], HEX);
Serial.println(readBuff[0], HEX);
write_register(0x1F, 0xFB, 5, writeBuff);
delay(2000);
}
这是STM32从机的I2C代码部分:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file i2c.c
* @brief This file provides code for the configuration
* of the I2C instances.
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
I2C_HandleTypeDef hi2c1;
/* I2C1 init function */
void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
// Get I2C address code from hardware jumpers
// Address starts at I2C_ADDRESS_BASE and is offset by value read on jumpers array
uint8_t I2C_Address = 0x0;
I2C_Address = (I2C_ADDRESS_BASE + (
(HAL_GPIO_ReadPin(AD0_GPIO_Port, AD0_Pin) << 0)|
(HAL_GPIO_ReadPin(AD1_GPIO_Port, AD1_Pin) << 1)|
(HAL_GPIO_ReadPin(AD2_GPIO_Port, AD2_Pin) << 2)|
(HAL_GPIO_ReadPin(AD3_GPIO_Port, AD3_Pin) << 3)
)) << 1;
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x0000020B;
hi2c1.Init.OwnAddress1 = I2C_Address;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_ENABLE;
hi2c1.Init.OwnAddress2 = (I2C_ADDRESS_BASE + 16) << 1;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C1_CLK_DISABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
/* I2C1 interrupt Deinit */
HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspDeInit 1 */
/* USER CODE END I2C1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
#define I2C_BUFFER_SIZE 8
uint8_t i2c_buffer[I2C_BUFFER_SIZE];
uint8_t reg_addr_rcvd = 0;
#define I2C_REG_ADD_SIZE 1
#define I2C_PAYLOAD_SIZE 4
extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode){
UNUSED(AddrMatchCode);
// If is master write, listen to necessary amount of bytes
if(TransferDirection == I2C_DIRECTION_TRANSMIT){
// First write request is always 1 byte of the requested reg address
// Will saved it on the first position of I2C_buffer
if(!reg_addr_rcvd){
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, (void*)i2c_buffer, I2C_REG_ADD_SIZE, I2C_FIRST_FRAME);
} else {
// If a subsequent write request is sent, will receve 4 bytes from master
// Save it on the rest of the buffer
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, (void*)i2c_buffer, I2C_PAYLOAD_SIZE, I2C_NEXT_FRAME);
}
}
else {
// If a read request is sent by the master, return the value of the data in the requested register that was saved on 1st
// position of the I2C buffer
HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, data_register[i2c_buffer[0]].mem_addr, data_register[i2c_buffer[0]].len, I2C_LAST_FRAME);
}
// Read address + data size. If it is a read command, data size will be zero
}
extern void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c){
// This is called after a master 'write' request. first time around it will be a register.
// Second time if its a write to register request, it will be a payload
if(!reg_addr_rcvd){
// If reg_addr_rcvd is false, means that it received a register
reg_addr_rcvd = 1;
} else {
// If reg_addr_rcvd is set, means that this callback was returned after the payload data has been received
reg_addr_rcvd = 0;
}
HAL_I2C_EnableListen_IT(hi2c);
HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin);
}
extern void HAL_I2C_ListenCpltCallback (I2C_HandleTypeDef *hi2c){
HAL_I2C_EnableListen_IT(hi2c);
HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin);
}
extern void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c){
// Reset reg_addr_rcvd after finish sending requested register
reg_addr_rcvd = 0;
HAL_I2C_EnableListen_IT(hi2c);
}
extern void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin);
//HAL_I2C_ERROR_NONE 0x00000000U /*!< No error */
//HAL_I2C_ERROR_BERR 0x00000001U /*!< BERR error */
//HAL_I2C_ERROR_ARLO 0x00000002U /*!< ARLO error */
//HAL_I2C_ERROR_AF 0x00000004U /*!< Ack Failure error */
//HAL_I2C_ERROR_OVR 0x00000008U /*!< OVR error */
//HAL_I2C_ERROR_DMA 0x00000010U /*!< DMA transfer error */
//HAL_I2C_ERROR_TIMEOUT 0x00000020U /*!< Timeout Error */
uint32_t error_code = HAL_I2C_GetError(hi2c);
if (error_code != HAL_I2C_ERROR_AF){}
HAL_I2C_EnableListen_IT(hi2c);
}
/* USER CODE END 1 */
感谢你们的任何见解。谢谢!
最佳答案
你问了两个问题。这是对第一个问题的回答,这就是为什么你在读取 4 个数据字节后得到 nack?
这是绝对正确和预期的行为,无论如何它是由 Arduino 而不是 STM32 完成的。
解释一下:每个字节后的确认始终是未发送字节的一方的责任。当主机向从机写入地址或数据时,如果从机收到该字节并准备好开始发送下一个字节,则从机生成确认。
当主机从从机读取数据时,从机(STM32)发送数据字节,由主机(Arduino)负责选择发送ack或nack。如果 master 发送一个 ack 表示“我已经收到这个字节,准备再给我发送一个字节”。如果 master 发送 nack 表示“我已经完成了从你那里获取数据”。
在 I2C 中,在不知道需要多少字节的情况下开始读取是完全合法的,在这种情况下,您将确认每个字节,然后在您读取足够多的内容时发送停止条件。但是,在您的情况下,您预先告诉 Arduino 它应该读取 4 个字节,因此它会继续确认前三个字节并确认第四个字节。
在某些情况下,这种行为可以节省从端的资源,因为从端立即知道它不需要准备好第五个字节。
关于c - 为什么 STM32 I2C 从机返回不需要的 NACK 或无限期延长时钟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74172080/
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
在编码时,我问了自己这个问题: 这样更快吗: if(false) return true; else return false; 比这个? if(false) return true; return
如何在逻辑条件下进行“返回”? 在这样的情况下这会很有用 checkConfig() || return false; var iNeedThis=doSomething() || return fa
这是我的正则表达式 demo 如问题所述: 如果第一个数字是 1 则返回 1 但如果是 145 则返回 145 但如果是 133 则返回 133 样本数据a: K'8134567 K'81345678
在代码高尔夫问答部分查看谜题和答案时,我遇到了 this solution返回 1 的最长和最晦涩的方法 引用答案, int foo(void) { return! 0; } int bar(
我想在下面返回 JSON。 { "name": "jackie" } postman 给我错误。说明 Unexpected 'n' 这里是 Spring Boot 的新手。 1日龄。有没有正确的方法来
只要“is”返回 True,“==”不应该返回 True 吗? In [101]: np.NAN is np.nan is np.NaN Out[101]: True In [102]: np.NAN
我需要获取所有在 6 号或 7 号房间或根本不在任何房间的学生的详细信息。如果他们在其他房间,简单地说,我不希望有那个记录。 我的架构是: students(roll_no, name,class,.
我有一个表单,我将它发送到 php 以通过 ajax 插入到 mysql 数据库中。一切顺利,php 返回 "true" 值,但在 ajax 中它显示 false 消息。 在这里你可以查看php代码:
我在 Kotlin 中遇到了一个非常奇怪的无法解释的值比较问题,以下代码打印 假 data class Foo ( val a: Byte ) fun main() { val NUM
请注意,这并非特定于 Protractor。问题在于 Angular 2 的内置 Testability service Protractor 碰巧使用。 Protractor 调用 Testabil
在调试窗口中,以下表达式均返回 1。 Application.WorksheetFunction.CountA(Cells(4 + (i - 1) * rows_per_record, 28) & "
我在本地使用 jsonplaceholder ( http://jsonplaceholder.typicode.com/)。我正在通过 extjs rest 代理测试我的 GET 和 POST 调用
这是 Postman 为成功调用我的页面而提供的(修改后的)代码段。 var client = new RestClient("http://sub.example.com/wp-json/wp/v2
这个问题在这里已经有了答案: What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must
我想我对 C 命令行参数有点生疏。我查看了我的一些旧代码,但无论这个版本是什么,都会出现段错误。 运行方式是 ./foo -n num(其中 num 是用户在命令行中输入的数字) 但不知何故它不起作用
我已经编写了一个类来处理命名管道连接,如果我创建了一个实例,关闭它,然后尝试创建另一个实例,调用 CreateFile() 返回 INVALID_HANDLE_VALUE,并且 GetLastErro
即使 is_writable() 返回 true,我也无法写入文件。当然,该文件存在并且显然是可读的。这是代码: $file = "data"; echo file_get_contents($fil
下面代码中的变量 $response 为 NULL,尽管它应该是 SOAP 请求的值。 (潮汐列表)。当我调用 $client->__getLastResponse() 时,我从 SOAP 服务获得了
我一直在网上的不同论坛上搜索答案,但似乎没有与我的情况相符的... 我正在使用 Windows 7,VS2010。 我有一个使用定时器来调用任务栏刷新功能的应用程序。在该任务栏函数中包含对 LoadI
我是一名优秀的程序员,十分优秀!