找回密码
 立即注册
查看: 55|回复: 7

使用ai801u通过硬件i2c沟通外部adc采集电压信号,最终将数据通过usb传入pc端

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层 |阅读模式
大佬们好,我接触单片机一小段时间,但苦于身边没有人可以请教,特此发帖。


本人使用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[0] == 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;
}

long  ADC_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;


/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void IIC_Start()
{
        busy = 1;
        I2CMSCR = 0x81;
        while(busy);
}
/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void IIC_Stop()
{
        busy = 1;
        I2CMSCR = 0x86;
        while(busy);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void IIC_SendByte(char Data)
{
        I2CTXD = Data;
        busy = 1;
        I2CMSCR = 0x82;
        while(busy);
       
}

/**
  * @brief  I2C接收一个字节
  * @param  无
  * @retval 接收到的一个字节数据
  */
char IIC_ReceiveByte()
{
        busy = 1;
        I2CMSCR = 0x84;
        while(busy);
        return I2CRXD;
}

/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void IIC_SendAck()
{
        I2CMSST = 0x00;
        busy = 1;
        I2CMSCR = 0x85;
        while(busy);
}

/**
  * @brief  I2C接收应答位
  * @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


回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层
国芯人工智能 发表于 2025-8-11 17:18
尊敬的开发者您好,感谢您的详细描述。针对您在使用AI801U单片机通过硬件I2C与外部ADC通信,并将采集数据通 ...

来个专人看一下吧,拜托了,这个ai都没看完我发的内容呀
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:526
  • 最近打卡:2025-08-13 09:45:20
已绑定手机

86

主题

5898

回帖

1万

积分

超级版主

积分
10659
发表于 3 天前 | 显示全部楼层
下载最新版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

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层
Debu*** 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
排查常见问题,发现打开了 ...

有中断函数的,写在i2c部分了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层
Debu*** 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
排查常见问题,发现打开了 ...

截图202508111944135250.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层
Debu*** 发表于 2025-8-11 19:37
下载最新版USB库:
https://www.stcaimcu.com/data/do ... STC_USB_LIBRARY.zip
供参考I2C程序的例程:

请问一下大佬,ai8051u的硬件i2c不需要将引脚配置为开漏输出吗?例程里是配置为准双向口,另外我的代码里看了一下逻辑,我个人觉得时间上应该不会出现中断函数优先级的问题,但是否需要更改优先级,或者写中断函数保护呢?这个保护是按什么思路来写呢?我没有查到类似的例程,只是知道有个中断函数保护和什么堆栈保护

点评

准双向口并写1(IO默认就是1),发送时0变1有两个强上拉加速IO翻转,接收时等效于开漏+弱上拉,当然,就算是准双向,内部4K上拉也是建议打开的,加快上升沿速度,准双向的弱上拉等效几十K上百K电阻,太大了,挂多个I  详情 回复 发表于 3 天前
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:526
  • 最近打卡:2025-08-13 09:45:20
已绑定手机

86

主题

5898

回帖

1万

积分

超级版主

积分
10659
发表于 3 天前 | 显示全部楼层
youzai*** 发表于 2025-8-11 19:54
请问一下大佬,ai8051u的硬件i2c不需要将引脚配置为开漏输出吗?例程里是配置为准双向口,另外我的代码里 ...

准双向口并写1(IO默认就是1),发送时0变1有两个强上拉加速IO翻转,接收时等效于开漏+弱上拉,当然,就算是准双向,内部4K上拉也是建议打开的,加快上升沿速度,准双向的弱上拉等效几十K上百K电阻,太大了,挂多个I2C从机或高速通信(400K或以上)还没有外部电阻上拉的情况下不稳定
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-08-13 11:24:48
已绑定手机

3

主题

3

回帖

51

积分

注册会员

积分
51
发表于 3 天前 | 显示全部楼层
Debu*** 发表于 2025-8-11 20:11
准双向口并写1(IO默认就是1),发送时0变1有两个强上拉加速IO翻转,接收时等效于开漏+弱上拉,当然,就 ...

好的谢谢大佬,那我配置成开漏吧,这样保险一点,外部电路有配置上拉电阻的
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-8-14 02:43 , Processed in 0.128028 second(s), 92 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表