第一步:使用EEPROM写入相应的数据
第二步:使用EEPROM读取相应的数据
第三步:使用CH341StreamI2C函数还原读取过程
每一步需要逻辑分析仪进行对比。
第一字节0x50对应24c16的地址(7位地址)(如果是8位地址对应的应该是0xA0)
第二字节0x00写地址
第3,4,5,6字节对应需要写入的数据。
此处多读取了一个字节(上面写入4个字节此处读取5个字节)操作界面如下
参考上面的波形分析,只是这里先写入了地址、寄存器地址、再读取地址,之后跟着数据。
注意此顺序在后续的CH341StreamI2C函数有对应关系。
使用CH341StreamI2C读取地址0xA0(8位地址,实际上是7位0x50地址运算后的值),寄存器地址0x02(此处不是从第0个寄存器读取),长度2对应的是数据长度
如果是那种寄存器地址需要2个字节的则此处长度应该修改位3(要给地址+两个寄存器地址)
波形分析:
第一个字节对应写入长度的第一个字节(下图中蓝色部分)
第二个字节对应下图中蓝色部分
第三个字节对应的还是地址
也就是说读取时自动发送第一个写入字节作为地址。
后面的5个字节时读取的数据字节
此处对应的实际值下图中蓝色部分
为了简化此处直接使用函数每个参数直接赋值的方式进行数据读取
使用的代码如下
m_swrdatalen = "2";// this.textBox_I2CSWRLen.Text;//写数据长度
m_srddatalen = "2";// this.textBox_I2CSRDLen.Text;//读数据长度
m_swrdatabuf = "9000";// this.textBox_I2CSWRDATA.Text;//写数据内容
m_swrdatalen = "2"; 读取温度时需要写入的两个字节(地址(i2c元器件8位表示的地址),以及寄存器地址)
m_swrdatabuf = "9000" 写入波形的前两个字节。(一个器件地址,一个寄存器地址)
m_srddatalen = "2"; 读取的数据长度
完整代码如下:(此处只是对LM75的读取处理,对于设备初始化等信息,参考官方完整代码,此处只是对CH341StreamI2C函数的参数进行解释)
private void button_ReadLM75A_Click(object sender, EventArgs e)
{
ReadLM75A();
}
public void ReadLM75A()
{
UInt32 mwlen = 0, mrlen = 0;
UInt32 k = 0;
UInt32 i = 0;
byte[] wrdatabuf;
byte[] mwBuf = new byte[CH341DLL.mMAX_BUFFER_LENGTH * 2];
byte[] wbuffer = new byte[CH341DLL.mMAX_BUFFER_LENGTH];
byte[] rbuffer = new byte[CH341DLL.mMAX_BUFFER_LENGTH];
string m_swrdatalen, m_srddatalen, m_swrdatabuf, m_srddatabuf;
m_swrdatalen = "2";// this.textBox_I2CSWRLen.Text;//写数据长度
m_srddatalen = "2";// this.textBox_I2CSRDLen.Text;//读数据长度
m_swrdatabuf = "9000";// this.textBox_I2CSWRDATA.Text;//写数据内容
m_srddatabuf = "";//待读取的数据
mwlen = mStrToBcd(m_swrdatalen); //写入数据长度
mrlen = mStrToBcd(m_srddatalen); //读取数据长度
if (mwlen == 0 && mrlen == 0)
{
MessageBox.Show("请输入长度", "CH341");
return;
}
else if ((m_swrdatabuf.Length) == 0 && (mwlen > 0))
{
MessageBox.Show("请输入要写入的数据", "CH341");
return;
}
else if (mrlen < 0)
{
MessageBox.Show("请输入读数据的长度", "CH341");
return;
}
if (mwlen >= 0x400 || mrlen >= 0x400)
{
MessageBox.Show("请输入小于0x400的长度", "CH341");
return;
}
if (mwlen > (m_swrdatabuf.Length) / 2)
mwlen = Convert.ToUInt32((m_swrdatabuf.Length) / 2);//在输入长度和数据长度中取小值
wrdatabuf = Encoding.Default.GetBytes(m_swrdatabuf);
mem_cpy(mwBuf, 0, wrdatabuf, 0, mwlen * 2);
mem_cpy(wbuffer, 0, mStrtoVal(mwBuf, mwlen * 2), 0, mwlen);
if (m_open)
{
try
{
if (!CH341DLL.CH341StreamI2C(mIndex, mwlen, wbuffer, mrlen, rbuffer))
{
this.textBox_I2CSWRLen.Text = k.ToString("x");
this.textBox_I2CSRDLen.Text = k.ToString("x"); //返回已读写的数据个数
MessageBox.Show("流模式读写数据失败!", "CH341");
}
else //发送成功
{
//this.textBox_I2CSWRLen.Text = mwlen.ToString("x");
//this.textBox_I2CSRDLen.Text = mrlen.ToString("x"); //返回已读写的数据个数
log(" 读取成功 ");
log("写入数据长度 " + mwlen.ToString("x"));
log("读取数据长度 " + mrlen.ToString("x"));
for (i = 0; i < mrlen; i++)
{
m_srddatabuf += rbuffer[i].ToString("x2").ToUpper() + " ";//两位十六进制数加一个空格
}
//this.richTextBox_LM75A.Text = m_srddatabuf;
log(" 读取的16进制数据 "+m_srddatabuf);
log(" 读取的温度数据 "+(LM75A(rbuffer[0] * 256 + rbuffer[1])).ToString("f3")+ "℃");
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
return;
}
}
else
{
MessageBox.Show("设备未打开!");
}
}
private void log(string msg)
{
this.richTextBox_LM75A.AppendText("\r\n" + DateTime.Now.ToString("HH:mm:ss:fff") + " -> " + msg);
}
private float LM75A(int zhi)
{
return (float)zhi / 32 * 5 / 4/10;
}
对于CH341StreamI2C函数的数据读取时写入的字节也是需要设置的(对应设置元器件地址,以及寄存器地址)
参考链接
CH341DS2.PDF - 南京沁恒微电子股份有限公司CH341技术手册2,USB总线转接芯片,接口丰富,平台驱动齐全,用于USB转串口/USB转并口/USB转打印口/USB转I2C两线串口。该手册为USB转并口及USB转同步串口的说明。https://www.wch.cn/downloads/CH341DS2_PDF.html
特此记录
anlog
2024年1月4日