找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2922|回复: 1
收起左侧

ACS712+51单片机电流测量程序与Proteus仿真图

[复制链接]
ID:679189 发表于 2022-5-13 17:14 | 显示全部楼层 |阅读模式
acs712+51单片机+DS18B20温度与电流测量电路与程序
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.gif

单片机源程序如下:
  1. #include<reg52.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. sbit DQ=P0^1; //ds18b20 与单片机连接口

  5. sbit RS=P1^0; //1602 写数据 / 写命令选择端口
  6. //RS=1 写数据,即要显示的内容
  7. //RS=0 写命令,即一些 LCD设置命令
  8. sbit RW=P1^1; //1602 读/ 写选择端, RW=0为写模式
  9. sbit EN=P1^2; // 给 EN一个高脉冲,将数据送入液晶控制器,完成写操作

  10. /******adc配置*****/
  11. sbit EOC_1543 = P3 ^ 7;
  12. sbit SCLK_1543 = P3 ^ 5;
  13. sbit ADDR_1543 = P3 ^ 3;
  14. sbit DOUT_1543 = P3 ^ 2;
  15. sbit CS_1543 = P3 ^ 4;

  16. uchar code str1[]={"cur:"};
  17. uchar code str2[]={"temp:"};
  18. uchar data disdata[4];// 百、十、个、小数位
  19. uchar data cur_c[3];

  20. uint tvalue; // 温度值
  21. uchar tflag; // 温度正负标志
  22. /**********************lcd1602 设置子函数 *********************/
  23. void delay1ms(uint ms) // 延时 1 毫秒子函数 ,形参为 ms(不够精确的)
  24. {
  25. unsigned int i,j;
  26. for(i=0;i<ms;i++)
  27. for(j=0;j<120;j++);
  28. }

  29. void delayus(unsigned char x)   // 延时 (x*2+5) us
  30. {
  31.     while(--x);
  32. }
  33. void wr_com(uchar com) //lcd 写控制指令子函数,形参为 com
  34. {
  35. delay1ms(1); // 调用延时子函数,并用实参 1 代替延时子函数中的形参 ms
  36. RS=0; //RS=0 进入写命令状态,即一些 LCD设置命令
  37. RW=0; //RW=0 为写模式
  38. EN=0;  //EN=0 时不能完成写操作
  39. P2=com; // 把要设置的指令码 com送给 P2 口
  40. delay1ms(1);
  41. EN=1; // 给 EN一个高脉冲,将数据送入液晶控制器,完成写操作
  42. delay1ms(1);
  43. EN=0; }//EN=0 时不能完成写操作
  44. /******************检测忙标志函数***************************/  
  45. void check_busy(void)
  46. {
  47.   uchar dt;
  48.   do
  49. {
  50.               dt=0xff;
  51.               EN=0;
  52.               RS=0;
  53.               RW=1;
  54.               EN=1;
  55.               dt=P2;
  56.               }while(dt&0x80);
  57.               EN=0;
  58. }

  59. //*****************写数据*******************************/
  60. void wr_dat(uchar dat) //lcd 写显示数据子函数,形参为 dat
  61. {
  62. /* check_busy();*/
  63. delay1ms(1);
  64. RS=1; //RS=1 进入写数据状态,即要显示的内容
  65. RW=0; //RW=0 为写模式
  66. EN=0; //EN=0 时不能完成写操作
  67. P2=dat; // 把要显示的数据 dat 送给 P2 口
  68. delay1ms(1);
  69. EN=1; // 给 EN一个高脉冲,将数据送入液晶控制器,完成写操作
  70. delay1ms(1);
  71. EN=0; //EN=0 时不能完成写操作
  72. }
  73. void lcd_init() //lcd 初始化设置子函数,不带参数 ,0x38 是显示模式设置 , 其余是显示开 / 关及光标设置,无顺序
  74. {
  75. delay1ms(15);
  76. wr_com(0x38); // 调用写控制指令子函数,并用实参 "0011 1000" 代替形参 com
  77. //0x38 表示设置为 16*2 显示,每个块为 5*7 点阵, 8 位数据接口
  78. delay1ms(5);
  79. wr_com(0x08); // 调用写控制指令子函数,并用实参 "0000 1000" 代替形参 com
  80. //0x08 表示设置为关显示、不显示光标、光标不闪烁
  81. delay1ms(5);
  82. wr_com(0x01); // 调用写控制指令子函数,并用实参 "0000 0001" 代替形参 com
  83. //0x01 表示显示数据清屏(数据指针清 0,所有显示清 0)
  84. delay1ms(5);
  85. wr_com(0x06);// 调用写控制指令子函数,并用实参 "0000 0110" 代替形参 com
  86. //0x06 表示当读或写一个字符后地址指针加 1,且光标加 1; 当写一个字符时,整屏显示不移动
  87. delay1ms(5);
  88. wr_com(0x0c);// 调用写控制指令子函数,并用实参 "0000 1100" 代替形参 com
  89. //0x0c 打开显示、不显示光标、光标不闪烁
  90. delay1ms(5);
  91. }
  92. void display(uchar *p) //lcd 显示字符串子函数
  93. {
  94. while(*p!='\0') // 测试是否等于 '\0' ,即判断字符是否结尾
  95. {
  96. wr_dat(*p); // 显示指针所指的字符串
  97. p++; // 指针加 1
  98. delay1ms(1);
  99. }
  100. }
  101. void init_play() // 初始化显示子函数
  102. {
  103. lcd_init(); // 调用 lcd 初始化设置子函数,对 LCD进行初始化
  104. wr_com(0x80); // 调用写控制指令子函数,并用实参 "1000 0000" 代替形参 com
  105. // 并将数据指针定位到第一行第一个字符处
  106. display(str1);// 从第一行第一个字符处显示字符串 str1
  107. wr_com(0x80+0x40);// 调用写控制指令子函数,并用实参 "1000 0000" 代替形参 com
  108. // 并将数据指针定位到第二行第一个字符处
  109. display(str2); // 从第二行第一个字符处显示字符串 str2
  110. }

  111. /********************************************************/
  112. /********************ds18b20 程序 ***********************/
  113. void delay_18b20(uint i) // 延时 1 微秒
  114. {
  115. while(i--);
  116. }
  117. void ds18b20rst() //ds18b20 初始化子函数
  118. // 要求"数据线拉高 - 延时 - 数据线拉低 - 延时大于 480 微妙 -数据线拉高 - 延时等待 "
  119. {
  120. uchar x=0;
  121. DQ = 1; // 信号线 DQ复位
  122. delay_18b20(4); // 延时
  123. DQ = 0; //DQ 拉低
  124. delay_18b20(100); // 精确延时大于 480us
  125. DQ = 1; // 拉高
  126. delay_18b20(40);
  127. }
  128. void ds18b20wr(uchar wdata) /* 写数据子函数 , 无返回值,含参数 */
  129. {
  130. uchar i=0;
  131. for (i=8; i>0; i--)// 要写完一个字节,故需要重复 8 次以下操作
  132. {
  133. DQ = 0; // 数据线拉低
  134. DQ = wdata&0x01;//wdata 是一个形参,将其与 0000 0001 进行按位与
  135. // 按从低到高的顺序发送数据(一次发送一位 )
  136. delay_18b20(10);
  137. DQ = 1; // 最后将数据线拉高
  138. wdata>>=1; // 将 wdata 右移 1 位
  139. }
  140. }
  141. uchar ds18b20rd() // 读数据子函数 , 是有返回值 dat
  142. {
  143. uchar i=0;
  144. uchar dat = 0;
  145. for (i=8;i>0;i--)// 要读完一个字节,故需要重复 8 次以下操作
  146. {
  147. DQ = 0; // 给脉冲信号
  148. dat>>=1;
  149. DQ = 1; // 给脉冲信号
  150. if(DQ)
  151. dat|=0x80;
  152. delay_18b20(10);
  153. }
  154. return(dat); // 返回 dat
  155. }
  156. read_temp() // 读取温度值并转换的子函数,有返回值温度值 tvalue
  157. {
  158. uchar a,b;
  159. ds18b20rst(); // 调用 ds18b20 初始化子函数
  160. ds18b20wr(0xcc);// 调用写数据子函数,向 ds18b20 写命令 0xcc
  161. //ccH 表示跳过 ROM读序列号,适用于单机工作,直接向 18b20 发送温度变换命令
  162. ds18b20wr(0x44);// 调用写数据子函数,向 ds18b20 写命令 0x44
  163. //44H 表示启动 ds18b20 温度转换 , 结果自行存入 9 字节的 RAM中
  164. ds18b20rst(); // 调用 ds18b20 初始化子函数
  165. ds18b20wr(0xcc);// 同上
  166. ds18b20wr(0xbe);// 调用写数据子函数,向 ds18b20 写命令 0xbe
  167. //beH 表示读取 RAM中 9 字节的温度数据
  168. a=ds18b20rd(); // 调用读数据子函数,并将所得数据给 a
  169. b=ds18b20rd(); //
  170. tvalue=b; // 把 b 的值给 tvalue
  171. tvalue<<=8; //tvalue 左移 8 位
  172. tvalue=tvalue|a;//tvalue 与 a 进行按位或
  173. if(tvalue<0x0fff)//
  174. tflag=0; // 前五位为 0 时,读取的温度为正,标志位为 0,此时只要
  175. // 将测得数值乘以 0.0625 即可得到实际温度
  176. else // 前五位为 1 时,读取的温度为负,标志位为 1,此时需要
  177. { // 将测得数值取反后再加 1,再乘以 0.0625 即可得到实际温度
  178. tflag=1; // 此时表示负温度
  179. tvalue=~tvalue+1;
  180. }
  181. tvalue=tvalue*(0.625);// 温度值扩大 10 倍,精确到 1 位小数
  182. return(tvalue); // 返回温度值
  183. }
  184. /**********************************************************/
  185. /************************ 温度值显示 *********************/
  186. void ds18b20disp() // 温度值显示
  187. {
  188. uchar flagdat;
  189. disdata[0]=tvalue/1000+0x30; // 百位数
  190. disdata[1]=tvalue%1000/100+0x30;// 十位数
  191. disdata[2]=tvalue%100/10+0x30; // 个位数
  192. disdata[3]=tvalue%10+0x30; // 小数位
  193. if(tflag==0)
  194. flagdat=0x2b; // 正温度显示符号 :+
  195. else
  196. flagdat=0x2d; // 负温度显示负号 :-
  197. if(disdata[0]==0x30)
  198. {
  199. disdata[0]=0x20; // 如果百位为 0,不显示
  200. if(disdata[1]==0x30)
  201. {
  202. disdata[1]=0x20; // 如果百位为 0,十位为 0 也不显示
  203. }
  204. }
  205. wr_com(0x80+0x46); // 定位数据指针的位置:第二行第五个字符处
  206. wr_dat(flagdat); // 显示符号位
  207. wr_com(0x80+0x47);  // 定位数据指针的位置:第二行第六个字符处
  208. wr_dat(disdata[0]);  // 显示百位
  209. wr_com(0x80+0x48);  // 定位数据指针的位置:第二行第七个字符处
  210. wr_dat(disdata[1]);  // 显示十位
  211. wr_com(0x80+0x49);  // 定位数据指针的位置:第二行第八个字符处
  212. wr_dat(disdata[2]);  // 显示个位
  213. wr_com(0x80+0x4A);  // 定位数据指针的位置:第二行第九个字符处
  214. wr_dat(0x2e); // 显示小数点
  215. wr_com(0x80+0x4B);  // 定位数据指针的位置:第二行第十个字符处
  216. wr_dat(disdata[3]);  // 显示小数位
  217.               /**********************显示摄氏度************************/
  218. wr_com(0x80+0x4C);  // 定位数据指针的位置:第二行第十一个字符处
  219. wr_dat(0XDF);
  220. wr_com(0x80+0x4D);  // 定位数据指针的位置:第二行第十二个字符处
  221. wr_dat(0X43);
  222. }

  223. /**********************************************************/
  224. /********************TLC1543************************/
  225. void TLC1543_init(void)
  226. {
  227.         CS_1543 = 1;
  228.         SCLK_1543 = 0;
  229. }


  230. uint ReadADC_TLC1543(uchar ain)
  231. {
  232.         uchar t;
  233.         uint adc_value = 0;
  234.         ain <<= 4;

  235.         CS_1543 = 0;
  236.         for (t = 0; t < 10; t++)         // 将判断语句改为 temp<12
  237.         {                                       // 程序可移殖至 TLC2543.
  238.                 adc_value <<= 1;
  239.                 ain <<= 1;
  240.                 ADDR_1543 = CY;
  241.                 if (DOUT_1543)   adc_value += 1;
  242.                 SCLK_1543 = 1;
  243.                 delayus(1);
  244.                 SCLK_1543 = 0;
  245.         }
  246.         CS_1543 = 1;

  247.         return  adc_value;
  248. }

  249. uint get_cur()
  250. {
  251.         uint vol,cur_1;
  252.         vol = ReadADC_TLC1543(0) * 0.49; //输入adc电压的100倍。4.9=5(参照电压)*/1024(10位)*100(用于显示)
  253.         cur_1 = 5*vol-1250; //实际电流的100倍用于显示,cur_real=(vol_real-2.5)*5
  254.         return cur_1;
  255. }

  256. void displaycur(uint cur)
  257. {
  258.         cur_c[0] = cur/1000%10+0x30;
  259.         cur_c[1]= cur/100%100+0x30;
  260.     cur_c[2]= cur/10%10+0x30;
  261.         wr_com(0x80 + 0x07);  // 定位数据指针的位置:第一行第七个字符处
  262.         wr_dat(cur_c[0]);  // 显示十位
  263.         wr_com(0x80 + 0x08);  // 定位数据指针的位置:第一行第八个字符处
  264.         wr_dat(cur_c[1]);  // 显示个位
  265.         wr_com(0x80 + 0x09);  // 定位数据指针的位置:第一行第九个字符处
  266.         wr_dat(0x2e); // 显示小数点
  267.         wr_com(0x80 + 0x0A);  // 定位数据指针的位置:第一行第十个字符处
  268.         wr_dat(cur_c[2]);  // 显示小数位
  269.         wr_com(0x80 + 0x0C);  // 定位数据指针的位置:第二行第十二个字符处
  270.         wr_dat(0X41);
  271. }

  272. /*******************************************************/
  273. /******************** 主程序 *****************************/
  274. void main()
  275. {
  276. init_play();  // 调用 lcd 初始化显示子函数
  277. TLC1543_init();
  278. while(1)
  279. {
  280. read_temp(); // 调用 ds18b20 读取温度
  281. ds18b20disp(); // 调用温度显示子函数
  282. displaycur(get_cur());
  283. }
  284. }
复制代码
Keil5代码与Proteus8.8仿真下载:
51单片机电流测量.zip (92.19 KB, 下载次数: 120)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:1004160 发表于 2023-10-2 20:43 | 显示全部楼层
楼主,我测试交流电流,换了个激励源(就是一个圈圈的那种220V的),是测不到正确电流的。但是换了一个探针类型的就可以了,这是为什么?
1.png
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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