[技术讨论] 原创分享:STM8S003硬件I2C通信驱动12位DAC芯片MCP4725控制程序

[复制链接]
1598|5
 楼主| henangongda123 发表于 2021-4-24 16:18 | 显示全部楼层 |阅读模式
#申请原创# MCP4725模块是某宝上买的,调试了一下午,有个误区大家注意下,当器件地址是0x60、0x61时,注意要左移1位,实际器件地址是0xC0(写指令)、0xC1(读指令);其他地方还是以前踩过的STM8S硬件I2C坑,因为之前踩过,所以这次很容易就过去了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评论

@21小跑堂 :还有这要求啊 好吧  发表于 2021-4-26 10:24
感谢参与原创奖励活动,此篇文章因字数未达到800字(此项为硬性指标,代码不计入字数统计)所以暂未通过审核。选题很不错,可以试试丰富完善下哦!  发表于 2021-4-26 10:16
 楼主| henangongda123 发表于 2021-4-24 16:22 | 显示全部楼层
程序来了~
  1. /********** STM8S硬件I2C相关操作 **********/
  2. //初始化函数
  3. /***********************************************************
  4. 函数名: I2C_Init()
  5. 功  能: STM8S103 MCU硬件I2C初始化
  6.         (注: 主模式,两线连接,7位地址模式,10Kbps通信速率)
  7. 参  数: 无
  8. 返回值: 无
  9. ***********************************************************/
  10. void I2C_Init(void)
  11. {
  12.   I2C_CR1 &= 0xFE;           //PE=0,禁用硬件I2C模块(所有位置0)
  13.         CLK_PCKENR1 |= 0x01;        //使能I2C时钟
  14.         I2C_CR2 |= 0x80;           //I2C_CR2控制寄存器SWRST=1,软件复位硬件I2C模块
  15.         I2C_CR2 &= 0x7F;           //I2C_CR2控制寄存器SWRST=0,软件复位硬件I2C模块结束
  16.   I2C_FREQR = 0x02;           //配置I2C外设时钟2MHz
  17.         I2C_CCRH = 0x00;            //配置I2C为标准模式及速率
  18.         I2C_CCRL = 0x64;            //I2C通信速率半周期=((1/2)*100us=50us,速率=1/100us=10KHz
  19.         I2C_TRISER = 0x03;          //配置I2C上升时间寄存器,1000ns(SCL最大值)/500ns(2MHz周期)+1
  20.         I2C_CR1 |= 0x01;            //启动I2C硬件模块
  21. }
  22. /***********************************************************
  23. 函数名: MCP4725_Write()/SCL-PB4,SDA-PB5/器件地址:0xC0写指令,0xC1读指令
  24. 功  能: STM8S103 MCU通过硬件I2C通信向从设备MCP4725写入器件地址、数据
  25. 参  数: data_buff --- 欲写入的多字节数据指针
  26.                           data_len  --- 欲写入的多字节数据长度
  27. 返回值: 无
  28. ***********************************************************/
  29. void MCP4725_Write(uchar *data_buff,uchar data_len)
  30. {         
  31.         uchar temp;                 //定义一下,读取MCU状态寄存器用
  32.         uchar i;                    //定义一下,供循环使用
  33.         uint time;                  //定义一下,供等待延时用
  34.         //以下程序为I2C通信防锁死操作,非常重要!
  35.         if((PB_IDR&0x20) == 0x00)  //检测总线是否真的忙碌中(忙碌则SCL=1,SDA=0)
  36.         {
  37.                 I2C_CR1 &= 0xFE;         //PE=0,禁用硬件I2C模块,准备直接操作MCU端口
  38.                 PB_DDR |= 0x10;           //设置SCL端口为输出
  39.                 PB_CR1 |= 0x10;           //上拉输出
  40.                 for(i=0;i<9;i++)         //SCL端口发出9个时钟脉冲,让从设备MCP4725释放总线(恢复SDA=1)
  41.                 {
  42.                         PB_ODR &= (~0x10);      //SCL=0;
  43.                         delay_us(50);           //延时(I2C通信频率10KHz)
  44.                   PB_ODR |= 0x10;         //SCL=1
  45.                   delay_us(50);           //延时(I2C通信频率10KHz)
  46.                 }
  47.                 time = 500;               //变量赋值,准备延迟等待500次
  48.                 while(!(PB_IDR&0x20))     //等待数据线SDA=1
  49.                 {
  50.                   if(!--time)             //变量自减
  51.                   return;                 //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
  52.           }
  53.                 PB_DDR &= (~0x10);        //SCL端口恢复输入方式
  54.                 PB_CR1 &= (~0x10);        //浮空输入
  55.                 PB_ODR &= (~0x10);        //清零输出寄存器
  56.                 I2C_CR1 |= 0x01;         //重新启动硬件I2C模块,接管SCL、SDA端口
  57.                 return;                   //退出函数,放弃本次数据写操作
  58.         }
  59.         //以上程序为I2C通信防锁死操作,非常重要!
  60.         //以下程序为STM8S硬件I2C通信防BUSY锁死操作,非常重要!
  61.         if((I2C_SR3&0x02) == 0x02) //检测总线是否正确释放空闲中(总线正确释放则I2C_SR3状态寄存器BUSY=0,否则BUSY=1)
  62.         {
  63.                 I2C_CR2 |= 0x80;         //I2C_CR2控制寄存器SWRST=1,软件复位硬件I2C模块
  64.           I2C_CR2 &= 0x7F;         //I2C_CR2控制寄存器SWRST=0,软件复位硬件I2C模块结束
  65.                 I2C_FREQR = 0x02;         //配置I2C外设时钟2MHz
  66.                 I2C_CCRH = 0x00;          //配置I2C为标准模式及速率
  67.                 I2C_CCRL = 0x64;          //I2C通信速率半周期=((1/2)*100us=50us,速率=1/100us=10KHz
  68.           I2C_TRISER = 0x03;        //配置I2C上升时间寄存器,1000ns(SCL最大值)/500ns(2MHz周期)+1
  69.                 I2C_CR1 |= 0x01;          //启动I2C硬件模块
  70.                 return;                   //退出函数,放弃本次数据写操作
  71.         }
  72.         //以上程序为STM8S硬件I2C通信防BUSY锁死操作,非常重要!
  73.         I2C_CR2 &= 0xFB;           //关闭ACK应答(清零I2C_CR2控制寄存器ACK位,收到一个字节数据或地址后不返回应答)
  74.         time = 500;                 //变量赋值,准备延迟等待500次
  75.         while(I2C_SR3&0x02)         //检测总线是否忙碌中(I2C_SR3状态寄存器BUSY位=1表示总线上有通信/忙碌)
  76.         {
  77.                 if(!--time)               //变量自减
  78.                 return;                   //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
  79.         }
  80.         I2C_CR2 |= 0x01;            //发起始条件(置位I2C_CR2控制寄存器START位)
  81.         time = 500;                 //变量赋值,准备延迟等待500次
  82.         while(!(I2C_SR1&0x01))     //I2C_SR1状态寄存器SB位=1表示发送成功
  83.         {
  84.                 if(!--time)               //变量自减
  85.                 return;                   //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
  86.         }
  87.         delay_us(5);                //短暂延时
  88.         temp = I2C_SR1;             //读取状态寄存器I2C_SR1值
  89.         I2C_DR = 0xC0;              //发送MCP4725从设备地址,同时清除I2C_SR1中BFT位(SLAVE ADDRESS,末位R/W=0表示写操作)
  90.         time = 500;                 //变量赋值,准备延迟等待500次
  91.         while(!(I2C_SR1&0x02))     //I2C_SR1状态寄存器ADDR位=1时表示地址发送结束(主模式)
  92.         {
  93.                 if(!--time)               //变量自减
  94.                 return;                   //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
  95.         }
  96.         delay_us(5);                //短暂延时
  97.         temp = I2C_SR1;             //读取状态寄存器I2C_SR1数值
  98.         temp = I2C_SR3;            //清除状态寄存器I2C_SR1中ADDR标志位(地址已发送结束)
  99.         while(data_len)             //循环写入多字节数据
  100.         {
  101.                 I2C_DR = *data_buff;      //发送一字节数据
  102.           while(!(I2C_SR1&0x84));   //等待数据发送完毕(I2C_SR1状态寄存器TxE、BTF位为1时,表示发送时数据寄存器为空且数据字节发送完毕)
  103.                 data_buff++;              //准备写入下一字节数据
  104.                 data_len--;
  105.         }
  106.         I2C_CR2 |= 0x02;            //发停止条件(置位I2C_CR2控制寄存器STOP位///必须先清除I2C_SR1状态寄存器BTF位)
  107. }
  108. /***********************************************************
  109. 函数名: Voltage_Write()
  110. 功  能: STM8S103通过硬件I2C通信向 12位DAC芯片MCP4725写入输出电压数据
  111. 参  数: 无
  112. 返回值: 无
  113. ***********************************************************/
  114. void Voltage_Write(void)
  115. {
  116.         uint i;                     //定义一下,临时使用数据
  117.         i = Light_Brightness*40.96; //计算当前亮度对应12位DAC值
  118.         MCP4725_Data[0] = (i&0x0F00)>>8;//快速模式,不关断,获取电压DAC值高4位
  119.         MCP4725_Data[1] = i&0x00FF; //获取电压DAC值低8位
  120.         MCP4725_Write(MCP4725_Data,2);//写入12位电压DAC数值
  121. }

Prry 发表于 2021-4-25 11:39 | 显示全部楼层
赞!关于i2c地址,很易误解,主要是地址位问题。实质上,i2c器件的有效地址是7bit,不包括地址位!不同人写的i2c驱动接口,使用的地址不同,易入坑。
如Linux、RT-Thread的i2c驱动地址使用的是7bit,在驱动内部做处理;一些个人编写的模拟i2c使用8bit地址(包括读写位)。另外也要注意芯片手册描述的i2c地址,
通常描述的都是7bit,也见过有个别描述的是8bit。区分7bit还是8bit地址,如果值大于0x7F,肯定是8bit地址了;最可靠的判断就是看时序图!
建议,i2c驱动库入口函数的i2c地址保留为7bit,读写位由驱动内部处理,用户只传入标准7bit地址,避免入坑。
 楼主| henangongda123 发表于 2021-4-25 11:54 | 显示全部楼层
Prry 发表于 2021-4-25 11:39
赞!关于i2c地址,很易误解,主要是地址位问题。实质上,i2c器件的有效地址是7bit,不包括地址位!不同人 ...

高!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

2115

帖子

19

粉丝
快速回复 在线客服 返回列表 返回顶部