使用ai801u通过硬件i2c沟通外部adc采集电压信号,最终将数据通过usb传入pc端
大佬们好,我接触单片机一小段时间,但苦于身边没有人可以请教,特此发帖。本人使用ai801u做一个项目,内容是通过硬件i2c沟通外部adc采集电压信号,并最终将数据通过usb传入pc端。结果是可以采集到一些电压信号,换算过来也是正确的,但是部分电压信号采集不到。不清楚是什么原因,个人猜测是不是中断函数优先级需要额外编写代码,又或者usb协议有什么不通的地方。本人之前用stc89c52做这个项目,但是因为位数不够所以才更换的单片机,但那时候并没有出现过测不到数据的情况。
如果需要实际表现的数据,需要明天去到实验室内上电测试一下。
我使用的是中断模式沟通硬件i2c,usb用的也是官方的库文件去配置,应该同属于中断函数。
我现在的问题在于,我查阅了官网上很多的资料包括官方例程,但是首先跟我类似的做法似乎很少,硬件i2c的例程也是很少;其次i2c协议是使用的开漏输出,但是例程里io口全部都配置为0x00,我也查不到哪里有说硬件i2c跟i2c协议有什么不同。下面贴出我编写的代码,烦请大佬们指正,万分感谢。
主函数部分:
#include "AI8051U.H"
#include "ADC.h"
#include "Delay.h"
#include "stc32_stc8_usb.h"
bit CommandByte;
long Data;
int main (void)
{
EAXFR = 1; //,使能访问XFR
WTST = 0;
CKCON = 0;
P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
P2M0 = 0x00; P2M1 = 0x00; //引脚23、24作为sda和scl
usb_init();
EA = 1; //使能中断
IE2 |= 0x80; //USB中断使能
I2CMSCR = 0x80; //主机模式I2C中断使能
I2CCFG = 0XDC; //使能I2C主机模式 此处应当是控制速度
I2CPSCR = 0x00; //时钟分频寄存器
I2CMSST = 0x00;
PUSBH = 1;PUSB = 0;
PI2CH = 1;PI2C = 1;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady)
{
unsigned char IE2_bak; // 保存IE2的临时变量
IE2_bak = IE2; // 保存当前IE2值
IE2 |= 0x80;
if(UsbOutBuffer == 0XAA) //判定触发条件
{
CommandByte = 1;
usb_OUT_done();
}
IE2 = IE2_bak; // 恢复IE2值
}
if(CommandByte)
{
ADC_WriteControl();
Data = ADC_ReadData();
Delay(1);
USB_SendData((unsigned char *) & Data ,sizeof( Data ));
CommandByte = 0;
}
}
}
ADC部分:
#include "IIC.h"
#include "Delay.h"
#define ADC_AddressReceive 0x48
#define ADC_AddressRead 0x49
#define ADC_channel 0xB0
int ADC_WriteControl()
{
IIC_Start();
IIC_SendByte(ADC_AddressReceive);
IIC_ReceiveAck();
IIC_SendByte(ADC_channel);
IIC_ReceiveAck();
return ADC_AddressRead;
}
longADC_ReadData()
{
long Data = 0;
unsigned char i;
IIC_Start();
IIC_SendByte(ADC_AddressRead);
IIC_ReceiveAck();
for (i = 0;i<3;i++)
{
Data<<=8;
Data |= IIC_ReceiveByte();
if(i<2)
{
IIC_SendAck();
}
else
{
IIC_SendNAk();
}
}
IIC_Stop();
return Data;
}
ADC头文件:
#ifndef __ADC_H__
#define __ADC_H__
int ADC_WriteControl();
long ADC_ReadData();
#endif
硬件iic中断模式:
#include "AI8051U.H"
#include "Delay.h"
sbit IIC_SCL=P2^4;
sbit IIC_SDA=P2^3;
bit busy;
/**
* @briefI2C开始
* @param无
* @retval 无
*/
void IIC_Start()
{
busy = 1;
I2CMSCR = 0x81;
while(busy);
}
/**
* @briefI2C停止
* @param无
* @retval 无
*/
void IIC_Stop()
{
busy = 1;
I2CMSCR = 0x86;
while(busy);
}
/**
* @briefI2C发送一个字节
* @paramByte 要发送的字节
* @retval 无
*/
void IIC_SendByte(char Data)
{
I2CTXD = Data;
busy = 1;
I2CMSCR = 0x82;
while(busy);
}
/**
* @briefI2C接收一个字节
* @param无
* @retval 接收到的一个字节数据
*/
char IIC_ReceiveByte()
{
busy = 1;
I2CMSCR = 0x84;
while(busy);
return I2CRXD;
}
/**
* @briefI2C发送应答
* @paramAckBit 应答位,0为应答,1为非应答
* @retval 无
*/
void IIC_SendAck()
{
I2CMSST = 0x00;
busy = 1;
I2CMSCR = 0x85;
while(busy);
}
/**
* @briefI2C接收应答位
* @param无
* @retval 接收到的应答位,0为应答,1为非应答
*/
void IIC_ReceiveAck()
{
busy = 1;
I2CMSCR = 0x83;
while(busy);
}
void IIC_SendNAk()
{
I2CMSST = 0x01;
busy = 1;
I2CMSCR = 0x85;
while(busy);
}
void I2C_Isr() interrupt 24
{
unsigned char EAXFR_bak;// 保存EAXFR的临时变量
EAXFR_bak = EAXFR; // 保存当前EAXFR值
EAXFR = 1; //修改当前EAXFR值
if(I2CMSST&0x40)
{
I2CMSST &= ~0x40;
busy = 0;
}
EAXFR = EAXFR_bak; // 恢复EAXFR值
}
硬件iic头文件:
#ifndef __IIC_H__
#define __IIC_H__
void IIC_Start();
void IIC_Stop();
void IIC_SendByte(char Data);
char IIC_ReceiveByte();
void IIC_SendAck();
void IIC_ReceiveAck();
void IIC_SendNAk();
void I2C_Isr();
#endif
延迟函数:
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
延迟函数头文件:
#ifndef __Delay_H__
#define __Delay_H__
void Delay(unsigned int xms);
#endif
国芯人工智能 发表于 2025-8-11 17:18
尊敬的开发者您好,感谢您的详细描述。针对您在使用AI801U单片机通过硬件I2C与外部ADC通信,并将采集数据通 ...
来个专人看一下吧,拜托了,这个ai都没看完我发的内容呀
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
供参考I2C程序的例程:
https://www.stcaimcu.com/thread-4612-1-1.html
https://www.stcaimcu.com/thread-4613-1-1.html
https://www.stcaimcu.com/thread-4698-1-1.html
一箭双雕I2C扫描:
https://www.stcaimcu.com/thread-9938-1-1.html
调试过程中可以在I2C时钟线上接LED(低电平有效)观察闪烁(微弱,仔细观察),I2C发送数据时可以看到LED闪烁表示IO模式和脚位切换正常
I2C_RecvACK后,读I2CMSST,如I2CMSST&MSACKI==0,说明从机有应答,此时I2C地址和时序都是正常的
如有逻辑分析仪或示波器,可直接测量信号看看
新手必读:
https://www.stcaimcu.com/thread-16535-1-1.html
DebugLab 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
排查常见问题,发现打开了 ...
有中断函数的,写在i2c部分了 DebugLab 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
排查常见问题,发现打开了 ...
DebugLab 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
供参考I2C程序的例程:
请问一下大佬,ai8051u的硬件i2c不需要将引脚配置为开漏输出吗?例程里是配置为准双向口,另外我的代码里看了一下逻辑,我个人觉得时间上应该不会出现中断函数优先级的问题,但是否需要更改优先级,或者写中断函数保护呢?这个保护是按什么思路来写呢?我没有查到类似的例程,只是知道有个中断函数保护和什么堆栈保护 youzaixiaoya 发表于 2025-8-11 19:54
请问一下大佬,ai8051u的硬件i2c不需要将引脚配置为开漏输出吗?例程里是配置为准双向口,另外我的代码里 ...
准双向口并写1(IO默认就是1),发送时0变1有两个强上拉加速IO翻转,接收时等效于开漏+弱上拉,当然,就算是准双向,内部4K上拉也是建议打开的,加快上升沿速度,准双向的弱上拉等效几十K上百K电阻,太大了,挂多个I2C从机或高速通信(400K或以上)还没有外部电阻上拉的情况下不稳定 DebugLab 发表于 2025-8-11 20:11
准双向口并写1(IO默认就是1),发送时0变1有两个强上拉加速IO翻转,接收时等效于开漏+弱上拉,当然,就 ...
好的谢谢大佬,那我配置成开漏吧,这样保险一点,外部电路有配置上拉电阻的
页:
[1]