找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4857|回复: 11
打印 上一主题 下一主题
收起左侧

stc32单片机modbus-rtu通讯源程序

  [复制链接]
跳转到指定楼层
#
单片机源程序如下:
  1. #include "stc32g.h" //头文件见下载软件

  2. #define MAIN_Fosc 11059200L //定义主时钟

  3. /************* 功能说明 **************

  4. 请先别修改程序, 直接下载"08-串口 1 中断收发-C 语言-MODBUS 协议"里的"UART1.hex"测试, 主频选择 11.0592MHZ.
  5. 测试正常后再修改移植.

  6. 串口 1 按 MODBUS-RTU 协议通信. 本例为从机程序, 主机一般是电脑端.

  7. 本例程只支持多寄存器读和多寄存器写, 寄存器长度为 64 个, 别的命令用户可以根据需要按 MODBUS-RTU 协议自行添
  8. 加.

  9. 本例子数据使用大端模式(与 C51 一致), CRC16 使用小端模式(与 PC 一致).

  10. 默认参数:
  11. 串口 1 设置均为 1 位起始位, 8 位数据位, 1 位停止位, 无校验.
  12. 串口 1(P3.0 P3.1): 9600bps.

  13. 定时器 0 用于超时计时. 串口每收到一个字节都会重置超时计数, 当串口空闲超过 35bit 时间时(9600bps 对应 3.6ms)则接
  14. 收完成.
  15. 用户修改波特率时注意要修改这个超时时间.

  16. 本例程只是一个应用例子, 科普 MODBUS-RTU 协议并不在本例子职责范围, 用户可以上网搜索相关协议文本参考.
  17. 本例定义了 64 个寄存器, 访问地址为 0x1000~0x103f.
  18. 命令例子:
  19. 写入 4 个寄存器(8 个字节):
  20. 10 10 1000 0004 08 1234 5678 90AB CDEF 4930
  21. 返回:
  22. 10 10 10 00 00 04 4B C6
  23. 读出 4 个寄存器:
  24. 10 03 1000 0004 4388
  25. 返回:
  26. 10 03 08 12 34 56 78 90 AB CD EF 3D D5

  27. 命令错误返回信息(自定义):
  28. 0x90: 功能码错误. 收到了不支持的功能码.
  29. 0x91: 命令长度错误.
  30. 0x92: 写入或读出寄存器个数或字节数错误.
  31. 0x93: 寄存器地址错误.

  32. 注意: 收到广播地址 0x00 时要处理信息, 但不返回应答.

  33. ******************************************/

  34. typedef unsigned char u8;

  35. typedef unsigned int u16;
  36. typedef unsigned long u32;

  37. /************* 本地常量声明 **************/
  38. #define RX1_Length 128 /* 接收缓冲长度 */
  39. #define TX1_Length 128 /* 发送缓冲长度 */


  40. //
  41. //
  42. //uint gnmbl=7;//1|?ü??±?á?
  43. u16  FREQ;              //
  44. float temp;
  45. //sbit OUTPUT1=P26;               //PWM1
  46. //sbit OUTPUT2=P27;
  47. /************* 本地变量声明 **************/
  48. u8 xdata RX1_Buffer[RX1_Length]; //接收缓冲
  49. u8 xdata TX1_Buffer[TX1_Length]; //发送缓冲

  50. u8 RX1_cnt; //接收字节计数.
  51. u8 TX1_cnt; //发送字节计数
  52. u8 TX1_number; //要发送的字节数
  53. u8 RX1_TimeOut; //接收超时计时器

  54. bit B_RX1_OK; // 接收数据标志
  55. bit B_TX1_Busy; // 发送忙标志


  56. /************* 本地函数声明 **************/
  57. void UART1_config(u32 brt, u8 timer, u8 io); // brt: 通信波特率, timer=2: 波特率使用定时器 2, 其它值: 使用 Timer1做波特率. io=0: 串口 1 切换到 P3.0 P3.1, =1: 切换到 P3.6 P3.7, =2: 切换到 P1.6 P1.7, =3: 切换到 P4.3 P4.4.
  58. u8 Timer0_Config(u8 t, u32 reload); //t=0: reload 值是主时钟周期数, t=1: reload 值是时间(单位 us), 返回 0 正确, 返回 1 装载值过大错误.
  59. u16 MODBUS_CRC16(u8 *p, u8 n);
  60. u8 MODBUS_RTU(void);



  61. #define SL_ADDR 0x01 /* 本从机站号地址 */
  62. #define REG_ADDRESS 0x0000 /* 寄存器首地址 */
  63. #define REG_LENGTH 64 /* 寄存器长度 */
  64. u16 xdata modbus_reg[REG_LENGTH]; /* 寄存器地址 */



  65. //========================================================================
  66. // 函数: void main(void)
  67. // 描述: 主函数
  68. // 参数: none.
  69. // 返回: none.
  70. // 版本: VER1.0
  71. // 日期: 2018-4-2
  72. // 备注:
  73. //========================================================================
  74. void main(void)
  75. {

  76. u8 i;
  77. u16 crc;

  78. EAXFR = 1; //使能访问 XFR
  79. WTST = 0x00; //设置程序代码等待参数,
  80. //赋值为 0 可将 CPU 执行程序的速度设置为最快

  81. Timer0_Config(0, MAIN_Fosc / 10000); //t=0: reload 值是主时钟周期数, (中断频率, 20000 次/秒)
  82. UART1_config(9600UL, 1, 0);// brt: 通信波特率, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口 1 切换到 P3.0 P3.1, =1: 切换到 P3.6 P3.7, =2: 切换到 P1.6 P1.7, =3: 切换到 P4.3 P4.4.
  83. //  init();
  84. Timer3_Init();
  85.         calculate_F();
  86. EA = 1;

  87.         while (1)
  88.         {
  89.                         if(B_RX1_OK && !B_TX1_Busy) //收到数据, 进行 MODBUS-RTU 协议解析
  90.                         {
  91.                                         if(MODBUS_CRC16(RX1_Buffer, RX1_cnt) == 0) //首先判断 CRC16 是否正确, 不正确则忽略, 不处理也不返回信息
  92.                                         {
  93.                                                         if((RX1_Buffer[0] == 0x00) || (RX1_Buffer[0] == SL_ADDR)) //然后判断站号地址是否正确, 或者是否广播地址(不返回信息)
  94.                                                         {
  95.                                                                 if(RX1_cnt > 2) RX1_cnt -= 2; //去掉 CRC16 校验字节
  96.                                                                         i = MODBUS_RTU(); //MODBUS-RTU 协议解析
  97.                                                                         if(i != 0) //错误处理
  98.                                                                         {
  99.                                                                                 TX1_Buffer[0] = SL_ADDR; //站号地址
  100.                                                                                 TX1_Buffer[1] = i; //错误代码
  101.                                                                                 crc = MODBUS_CRC16(TX1_Buffer, 2);
  102.                                                                                 TX1_Buffer[2] = (u8)(crc>>8); //CRC 是小端模式
  103.                                                                                 TX1_Buffer[3] = (u8)crc;
  104.                                                                                 B_TX1_Busy = 1; //标志发送忙
  105.                                                                                 TX1_cnt = 0; //发送字节计数
  106.                                                                                 TX1_number = 4; //要发送的字节数
  107.                                                                                 TI = 1; //启动发送
  108.                                                                         }
  109.                                                                 }
  110.                                                 }
  111.                                         RX1_cnt = 0;
  112.                                         B_RX1_OK = 0;
  113.                                 }
  114.                 }
  115. }



  116. /****************************** MODBUS_CRC (shift) *************** past test 06-11-27 *********
  117. 计算 CRC,调用方式 MODBUS_CRC16(&CRC,8); &CRC 为首地址,8 为字节数
  118. CRC-16 for MODBUS
  119. CRC16=X16+X15+X2+1
  120. TEST: ---> ABCDEFGHIJ CRC16=0x0BEE 1627T
  121. */
  122. //========================================================================
  123. // 函数: u16 MODBUS_CRC16(u8 *p, u8 n)
  124. // 描述: 计算 CRC16 函数.
  125. // 参数: *p: 要计算的数据指针.
  126. // n: 要计算的字节数.
  127. // 返回: CRC16 值.
  128. // 版本: V1.0, 2022-3-18 梁工
  129. //========================================================================
  130. u16 MODBUS_CRC16(u8 *p, u8 n)
  131. {
  132. u8 i;
  133. u16 crc16;

  134. crc16 = 0xffff; //预置 16 位 CRC 寄存器为 0xffff(即全为 1)
  135.         do
  136.         {
  137.                         crc16 ^= (u16)*p; //把 8 位数据与 16 位 CRC 寄存器的低位相异或,把结果放于 CRC 寄存器
  138.                         for(i=0; i<8; i++) //8 位数据
  139.                         {
  140.                                 if(crc16 & 1) crc16 = (crc16 >> 1) ^ 0xA001; //如果最低位为 0,把 CRC 寄存器的内容右移一位(朝低位),用 0填补最高位,
  141. //再异或多项式 0xA001
  142.                                 else crc16 >>= 1; //如果最低位为 0,把 CRC 寄存器的内容右移一位(朝低位),用 0 填补最高位
  143.                         }
  144.                         p++;
  145.                 }while(--n != 0);
  146. return (crc16);
  147. }

  148. /********************* modbus 协议 *************************/
  149. /***************************************************************************
  150. 写多寄存器
  151. 数据: 地址 功能码 寄存地址 寄存器个数 写入字节数 写入数据 CRC16
  152. 偏移: 0 1 2 3 4 5 6 7~ 最后 2 字节
  153. 字节: 1 byte 1 byte 2 byte 2 byte 1byte 2*n byte 2 byte
  154. addr 0x10 xxxx xxxx xx xx....xx xxxx

  155. 返回
  156. 数据: 地址 功能码 寄存地址 寄存器个数 CRC16
  157. 偏移: 0 1 2 3 4 5 6 7
  158. STC32G 系列技术手册 官方网站: STCMCUDATA
  159. 深圳国芯人工智能
  160. 字节: 1 byte 1 byte 2 byte 2 byte 2 byte
  161. addr 0x10 xxxx xxxx xxxx


  162. 读多寄存器
  163. 数据:站号(地址) 功能码    寄存地址        寄存器个数      CRC16
  164. 偏移: 0          1        2    3         4    5          6 7
  165. 字节: 1 byte     1 byte   2 byte         2 byte 2 byte
  166.      addr       0x03      xxxx           xxxx              xxxx

  167. 返回
  168. 数据:站号(地址) 功能码 读出字节数 读出数据 CRC16
  169. 偏移: 0 1 2 3~ 最后 2 字节
  170. 字节: 1 byte 1 byte 1byte 2*n byte 2 byte
  171. addr 0x03 xx xx....xx xxxx

  172. 返回错误代码
  173. 数据:站号(地址) 错误码 CRC16
  174. 偏移: 0 1 最后 2 字节
  175. 字节: 1 byte 1 byte 2 byte
  176. addr 0x03 xxxx
  177. ***************************************************************************/
  178. u8 MODBUS_RTU(void)
  179. {
  180. u8 i,j,k;
  181. u16 reg_addr; //寄存器地址
  182. u8 reg_len; //写入寄存器个数
  183. u16 crc;

  184. if(RX1_Buffer[1] == 0x06)//写多寄存器
  185. {
  186.                 if(RX1_cnt < 9) return 0x91; //命令长度错误
  187.                 if((RX1_Buffer[4] != 0) || ((RX1_Buffer[5] *2) != RX1_Buffer[6])) return 0x92; //写入寄存器个数与字节数错误
  188.                 if((RX1_Buffer[5]==0) || (RX1_Buffer[5] > REG_LENGTH)) return 0x92; //写入寄存器个数错误

  189.                 reg_addr = ((u16)RX1_Buffer[2] << 8) + RX1_Buffer[3]; //寄存器地址
  190.                 reg_len = RX1_Buffer[5]; //写入寄存器个数
  191.                 if((reg_addr+(u16)RX1_Buffer[5]) > (REG_ADDRESS+REG_LENGTH)) return 0x93; //寄存器地址错误
  192.                 if(reg_addr < REG_ADDRESS) return 0x93; //寄存器地址错误
  193.                 if((reg_len*2+7) != RX1_cnt) return 0x91; //命令长度错误

  194.                 j = reg_addr - REG_ADDRESS; //寄存器数据下标
  195.                 for(k=7, i=0; i<reg_len; i++,j++)
  196.                 {
  197.                         modbus_reg[j] = ((u16)RX1_Buffer[k] << 8) + RX1_Buffer[k+1]; //写入数据, 大端模式
  198.                         k += 2;

  199.                 }

  200.                 if(RX1_Buffer[0] != 0) //非广播地址则应答
  201.                 {
  202.                                 for(i=0; i<6; i++) TX1_Buffer[i] = RX1_Buffer[i]; //要返回的应答
  203.                                 crc = MODBUS_CRC16(TX1_Buffer, 6);
  204.                                 TX1_Buffer[6] = (u8)(crc>>8); //CRC 是小端模式
  205.                                 TX1_Buffer[7] = (u8)crc;
  206.                                 B_TX1_Busy = 1; //标志发送忙
  207.                                 TX1_cnt = 0; //发送字节计数
  208.                                 TX1_number = 8; //要发送的字节数
  209.                                 TI = 1; //启动发送
  210.                 }
  211. }
  212. else if(RX1_Buffer[1] == 0x03) //读多寄存器
  213. {
  214.                 if(RX1_Buffer[0] != 0) //非广播地址则应答
  215.                 {
  216.                                 if(RX1_cnt != 6) return 0x91; //命令长度错误
  217.                                 if(RX1_Buffer[4] != 0) return 0x92; //读出寄存器个数错误
  218.                                 if((RX1_Buffer[5]==0) || (RX1_Buffer[5] > REG_LENGTH)) return 0x92; //读出寄存器个数错误

  219.                                 reg_addr = ((u16)RX1_Buffer[2] << 8) + RX1_Buffer[3]; //寄存器地址
  220.                                 reg_len = RX1_Buffer[5]; //读出寄存器个数
  221.                                 if((reg_addr+(u16)RX1_Buffer[5]) > (REG_ADDRESS+REG_LENGTH)) return 0x93; //寄存器地址错误
  222.                                 if(reg_addr < REG_ADDRESS) return 0x93; //寄存器地址错误

  223.                                 j = reg_addr - REG_ADDRESS; //寄存器数据下标
  224.                                 TX1_Buffer[0] = SL_ADDR; //站号地址
  225.                                 TX1_Buffer[1] = 0x03; //读功能码
  226.                                 TX1_Buffer[2] = reg_len*2; //返回字节数

  227.                                 for(k=3, i=0; i<reg_len; i++,j++)
  228.                                 {
  229.                                         TX1_Buffer[k++] = (u8)(modbus_reg[j] >> 8);//数据为大端模式
  230.                                         TX1_Buffer[k++] = (u8)modbus_reg[j];
  231.                                 }
  232.                                 crc = MODBUS_CRC16(TX1_Buffer, k);
  233.                                 TX1_Buffer[k++] = (u8)(crc>>8); //CRC 是小端模式
  234.                                 TX1_Buffer[k++] = (u8)crc;
  235.                                 B_TX1_Busy = 1; //标志发送忙
  236.                                 TX1_cnt = 0; //发送字节计数
  237.                                 TX1_number = k; //要发送的字节数
  238.                                 TI = 1; //启动发送
  239.                 }
  240.         }

  241. else return 0x90; //功能码错误

  242. return 0; //解析正确
  243. }


  244. //========================================================================
  245. // 函数:u8 Timer0_Config(u8 t, u32 reload)
  246. // 描述: timer0 初始化函数.
  247. // 参数: t: 重装值类型, 0 表示重装的是系统时钟数, 其余值表示重装的是时间(us).
  248. // reload: 重装值.
  249. // 返回: 0: 初始化正确, 1: 重装值过大, 初始化错误.
  250. // 版本: V1.0, 2018-3-5
  251. //========================================================================
  252. u8 Timer0_Config(u8 t, u32 reload) //t=0: reload 值是主时钟周期数, t=1: reload 值是时间(单位 us)
  253. {
  254.         TR0 = 0; //停止计数

  255.         if(t != 0) reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL); //重装的是时间(us), 计算所需要的系统时钟数.
  256.         if(reload >= (65536UL * 12)) return 1; //值过大, 返回错误
  257.         if(reload < 65536UL) AUXR |= 0x80; //1T mode
  258.         else
  259.         {
  260.                         AUXR &= ~0x80; //12T mode
  261.                         reload = reload / 12;
  262.         }
  263.                 reload = 65536UL - reload;
  264.                 TH0 = (u8)(reload >> 8);
  265.                 TL0 = (u8)(reload);

  266.                 ET0 = 1; //允许中断
  267.                 TMOD &= 0xf0;
  268.                 TMOD |= 0; //工作模式, 0: 16 位自动重装, 1: 16 位定时/计数, 2: 8 位自动重装, 3: 16 位自动重装, 不可屏蔽中断
  269.                 TR0 = 1; //开始运行
  270.                 return 0;
  271. }

  272. //========================================================================
  273. // 函数: void timer0_ISR (void) interrupt TIMER0_VECTOR
  274. // 描述: timer0 中断函数.
  275. // 参数: none.
  276. // 返回: none.
  277. // 版本: V1.0, 2016-5-12
  278. //========================================================================
  279. void timer0_ISR (void) interrupt 1

  280. {
  281.         if(RX1_TimeOut != 0)
  282.         {
  283.                         if(--RX1_TimeOut == 0) //超时
  284.                         {
  285.                                 if(RX1_cnt != 0) //接收有数据
  286.                                 {
  287.                                         B_RX1_OK = 1; //标志已收到数据块
  288.                                 }
  289.                         }
  290.         }
  291. }


  292. //========================================================================
  293. // 函数: SetTimer2Baudraye(u16 dat)
  294. // 描述: 设置 Timer2 做波特率发生器。
  295. // 参数: dat: Timer2 的重装值.
  296. // 返回: none.
  297. // 版本: VER1.0
  298. // 日期: 2018-4-2
  299. // 备注:
  300. //========================================================================
  301. void SetTimer2Baudraye(u16 dat) // 选择波特率, 2: 使用 Timer2 做波特率, 其它值: 使用 Timer1 做波特率.
  302. {
  303. AUXR &= ~(1<<4); //Timer stop
  304. AUXR &= ~(1<<3); //Timer2 set As Timer
  305. AUXR |= (1<<2); //Timer2 set as 1T mode
  306. T2H = (u8)(dat >> 8);
  307. T2L = (u8)dat;
  308. IE2 &= ~(1<<2); //禁止中断
  309. AUXR |= (1<<4); //Timer run enable
  310. }


  311. //========================================================================
  312. // 函数: void UART1_config(u32 brt, u8 timer, u8 io)
  313. // 描述: UART1 初始化函数。
  314. // 参数: brt: 通信波特率.
  315. // timer: 波特率使用的定时器, timer=2: 波特率使用定时器 2, 其它值: 使用 Timer1 做波特率.
  316. // io: 串口 1 切换到的 IO, io=0: 串口 1 切换到 P3.0 P3.1, =1: 切换到 P3.6 P3.7, =2: 切换到 P1.6 P1.7, =3: 切换到 P4.3 P4.4.
  317. // 返回: none.
  318. // 版本: VER1.0
  319. // 日期: 2018-4-2
  320. // 备注:

  321. //========================================================================
  322. void UART1_config(u32 brt, u8 timer, u8 io) // brt: 通信波特率, timer=2: 波特率使用定时器 2, 其它值: 使用 Timer1做波特率. io=0: 串口 1 切换到 P3.0 P3.1, =1: 切换到 P3.6 P3.7, =2: 切换到 P1.6 P1.7, =3: 切换到 P4.3 P4.4.
  323. {
  324. brt = 65536UL - (MAIN_Fosc / 4) / brt;
  325. if(timer == 2) //波特率使用定时器 2
  326. {
  327.                 AUXR |= 0x01; //S1 BRT Use Timer2;
  328.                 SetTimer2Baudraye((u16)brt);
  329. }

  330. else //波特率使用定时器 1
  331. {
  332.                 TR1 = 0;
  333.                 AUXR &= ~0x01; //S1 BRT Use Timer1;
  334.                 AUXR |= (1<<6); //Timer1 set as 1T mode
  335.                 TMOD &= ~(1<<6); //Timer1 set As Timer
  336.                 TMOD &= ~0x30; //Timer1_16bitAutoReload;
  337.                 TH1 = (u8)(brt >> 8);
  338.                 TL1 = (u8)brt;
  339.                 ET1 = 0; // 禁止 Timer1 中断
  340.                 TR1 = 1; // 运行 Timer1
  341.         }
  342.         P_SW1 &= ~0xc0; //默认切换到 P3.0 P3.1
  343.         if(io == 1)
  344.         {
  345.                 P_SW1 |= 0x40; //切换到 P3.6 P3.7
  346.                 P3M1 &= ~0xc0;
  347.                 P3M0 &= ~0xc0;
  348.         }
  349.         else if(io == 2)
  350.         {
  351.                 P_SW1 |= 0x80; //切换到 P1.6 P1.7
  352.                 P1M1 &= ~0xc0;
  353.                 P1M0 &= ~0xc0;
  354.         }
  355.         else if(io == 3)
  356.         {
  357.                         P_SW1 |= 0xc0; //切换到 P4.3 P4.4
  358.                         P4M1 &= ~0x18;
  359.                         P4M0 &= ~0x18;
  360.         }
  361.         else
  362.         {
  363.                         P3M1 &= ~0x03;
  364.                         P3M0 &= ~0x03;

  365.         }

  366.         SCON = (SCON & 0x3f) | (1<<6); // 8 位数据, 1 位起始位, 1 位停止位, 无校验
  367. // PS = 1; //高优先级中断
  368.         ES = 1; //允许中断
  369.         REN = 1; //允许接收
  370. }


  371. //========================================================================
  372. // 函数: void UART1_ISR (void) interrupt UART1_VECTOR
  373. // 描述: 串口 1 中断函数
  374. // 参数: none.
  375. // 返回: none.
  376. // 版本: VER1.0
  377. // 日期: 2018-4-2
  378. // 备注:
  379. //========================================================================
  380. void UART1_ISR (void) interrupt 4
  381. {
  382.         if(RI)
  383.         {
  384.                 RI = 0;
  385.                         if(!B_RX1_OK) //接收缓冲空闲
  386.                         {
  387.                                 if(RX1_cnt >= RX1_Length) RX1_cnt = 0;
  388.                                 RX1_Buffer[RX1_cnt++] = SBUF;
  389.                                 RX1_TimeOut = 36; //接收超时计时器, 35 个位时间
  390.                         }
  391. }

  392.         if(TI)
  393.         {
  394.                         TI = 0;
  395.                         if(TX1_number != 0) //有数据要发
  396.                         {
  397.                                         SBUF = TX1_Buffer[TX1_cnt++];
  398.                                         TX1_number--;
  399.                         }
  400.                         else B_TX1_Busy = 0;
  401.         }
  402. }
复制代码

STC32G.H头文件下载: STC32-MODBUSRTU.zip (97.02 KB, 下载次数: 222)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏11 分享淘帖 顶1 踩
回复

使用道具 举报

11#
ID:419072 发表于 2023-12-13 16:31 | 只看该作者
楼主的程序,报错的那两条注释掉就可以了,一个tim3的初始化,一个计算什么
回复

使用道具 举报

10#
ID:933601 发表于 2023-11-30 20:43 | 只看该作者

感谢楼主无私开源
回复

使用道具 举报

9#
ID:1091922 发表于 2023-10-28 00:15 | 只看该作者
大漠孤烟001 发表于 2023-1-3 15:39
绝对精华,爱的奉献

这个好,完整。
回复

使用道具 举报

8#
ID:883242 发表于 2023-1-28 10:40 | 只看该作者
wjfc123 发表于 2023-1-28 07:46
能告诉我那个modbus程序是如何自定义发送数据的?好似没有看到数据入口,想移植,奈何没看明白

这部分应该没写,modbus_reg[]既是接收缓冲区也是发送缓冲区,没找到写操作,只能说把接收数据又发回去了,只是个测试代码,要想好用,你要自行添加写数据的内容。
回复

使用道具 举报

7#
ID:1057468 发表于 2023-1-28 07:46 | 只看该作者
大漠孤烟001 发表于 2023-1-3 15:39
绝对精华,爱的奉献

能告诉我那个modbus程序是如何自定义发送数据的?好似没有看到数据入口,想移植,奈何没看明白
回复

使用道具 举报

6#
ID:1060196 发表于 2023-1-3 19:38 | 只看该作者
向大佬致敬!向大佬学习!!
回复

使用道具 举报

5#
ID:1042619 发表于 2023-1-3 15:39 | 只看该作者
     绝对精华,爱的奉献

STC8G系列-串口相关程序.rar

274.11 KB, 下载次数: 74

回复

使用道具 举报

地板
ID:1022244 发表于 2022-12-31 11:05 | 只看该作者
编译都通不过,也是不完整
回复

使用道具 举报

板凳
ID:476652 发表于 2022-12-31 10:46 | 只看该作者
NB的大佬!!向大佬致敬!向大佬学习!!
回复

使用道具 举报

沙发
ID:915491 发表于 2022-6-19 09:18 | 只看该作者
雪玉寐影 发表于 2022-5-4 18:15
一晃眼差点看成了stm32!

正好下载,谢谢
回复

使用道具 举报

楼主
ID:99525 发表于 2022-5-4 18:15 | 只看该作者
一晃眼差点看成了stm32!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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