尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于STM32F103C8T6与ST7540的电力线载波远程抄表系统设计

基于STM32F103C8T6与ST7540的电力线载波远程抄表系统设计 简介这份资源是一份面向电子信息、自动化及电气工程专业学生与嵌入式开发初学者的完整毕业设计/课设文档围绕单片机智能电表抄表系统的软硬件实现展开适合需要参考课题方案、撰写论文或搭建电力载波通信实验的读者。压缩包内为1个docx文件约1.57MB涵盖摘要、绪论、总体方案设计、硬件电路设计、软件代码编写与调试等章节涉及STM32F103C8T6主控、ST7540电力线载波modem、MAX232电平转换等核心器件的选型与外围电路分析。文档结合FSK调制解调通信技术给出电路原理图绘制、各功能模块解析及软硬件联调思路可帮助读者理解抄表电路板从方案论证到调试落地的完整流程。该系统具备可靠性高、可扩展性强、成本低、计量准确等特点主要应用于居民住宅电量的自动检测、收费与管理。目前已有84人学习下载适合作为嵌入式电力抄表方向课题设计、论文写作与实验参考的材料。1. 从一户一表到一台 PC抄表链路上的断点在哪一个 600 户的老小区抄表员每月要爬十几栋楼抄完还得回去手工录入。问题不在于爬楼累而在于数据链路是断的——电表读数和收费系统之间中间靠人当传输介质错抄、漏抄、抄多抄少都从这里来。这套设计给的答案很直接STM32F103C8T6 当控制核心ST7540 当电力线载波调制解调器把电量数据调制成载波信号直接耦合到既有的 220V 电力线上不额外架设通信线。终端侧电表把读数存进 EEPROM掉电不丢PC 端串口助手当管理平台按一对多主从轮询的方式挨个点名取数。它的适用边界要说清楚电力载波信号被配电变压器阻隔一套系统只能覆盖同一个台区三相电力线之间存在 10dB30dB 的信号损失工程上一般只走单相。适合做单片机课程设计、毕业设计或者想低成本验证远传抄表原型的人。2. STM32F103C8T6 与 ST7540 的载波前端电路设计2.1 主控与载波芯片的分工与选型理由STM32F103C8T6 是 LQFP48 封装、Cortex-M3 内核的 32 位 RISC 处理器最高 72MHz片内 64K Flash 加 20K SRAM。放到这套系统里真正被看中的是外设数量3 个 USART、2 个 SPI、2 个 I2C、3 个 16 位定时器加 1 个高级定时器。串口刚好够分——一路给 PC 侧的电平转换芯片一路给 ST7540I2C 一路挂 EEPROM不用做软件模拟。ST7540 的定位是电力线载波 modem。单电源 7.512.5V 供电内部集成了线路驱动器和 5V、3.3V 两个线性调整器最大输出电流 50mA静态电流约 5mA。它自带 8 个可编程发送频率、最高 4800bps 的可编程波特率、500μV(rms) 的接收灵敏度向下兼容 ST7538 和 ST7537做升级替换时改动小。内部功放已经集成外围不需要再搭大功率驱动级这是选它而不是MCU 独立调制电路 功放三段式方案的主要原因。引脚资源的实际分配如下这张表在画原理图前最好先定死后面改线很麻烦。功能STM32 引脚外设/模式关键参数PC 通信PA9 / PA10USART1_TX / RX接 MAX232最高 4.5Mbit/sST7540 通信PA2 / PA3USART2_TX / RX接载波模块本设计跑 4800bpsEEPROMPB6 / PB7I2C1_SCL / SDA开漏输出外部上拉程序烧录调试PA13 / PA14SWDIO / SWCLK优先 SWD不用 JTAG复位NRST异步复位低电平有效启动选择BOOT0 / PB2BOOT1决定启动映射2.2 最小系统8M 晶振、复位、启动模式与 SWD 烧录外部 8M 晶振接在 OSC_IN / OSC_OUT 上经 PLL 九倍频得到 72MHz。如果为了省料去掉外部晶振改用内部 RC48 脚封装下有两个处理方式把 OSC_IN、OSC_OUT 各串 10K 电阻接地来提高 EMC 性能或者把这两个脚重映射成 PD0、PD1 并配置为推挽输出低电平后者能省掉两个电阻。代价是内部 RC 的温漂和精度都差一档跑 4800bps 串口还凑合再往上就容易出误码。复位电路的作用是在上电时产生足够宽的低电平NRST 被拉低的这段时间里内部寄存器和片内 SRAM 被重设电平回升后 PC 指针从 0 地址取指。看门狗溢出时也是往这里灌高电平强制复位所以复位脚不要挂大电容否则看门狗复位会被拖慢。BOOT0 的接法是最容易踩坑的一处。常见做法是经 10K 电阻接地从片内 Flash 启动程序烧完直接跑要烧录时才把 BOOT0 拉到 3.3V 进系统存储器走串口 ISP 下载。如果 BOOT0 长期拉高又没接对 BOOT1上电后不会进你的应用程序现象是程序明明烧进去了却不动。时钟树配置建议直接操作寄存器逻辑比库函数清楚/* 8MHz 外部晶振 - PLL 9 倍频 - 72MHz 系统时钟 */ RCC-CR | RCC_CR_HSEON; while (!(RCC-CR RCC_CR_HSERDY)); /* 等 HSE 稳定 */ FLASH-ACR | FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2; /* 72MHz 需 2 个等待周期 */ RCC-CFGR ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL); RCC-CFGR | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9; /* HSE 不分频9 倍频 */ RCC-CFGR | RCC_CFGR_PPRE1_DIV2; /* APB1 最高 36MHz */ RCC-CFGR | RCC_CFGR_PPRE2_DIV1; /* APB2 保持 72MHz */ RCC-CR | RCC_CR_PLLON; while (!(RCC-CR RCC_CR_PLLRDY)); RCC-CFGR | RCC_CFGR_SW_PLL; /* 切系统时钟到 PLL */ while ((RCC-CFGR RCC_CFGR_SWS) ! RCC_CFGR_SWS_PLL);参数上要盯住 APB1 和 APB2 的分频。USART1 挂在 APB2 上跑 72MHzUSART2 挂在 APB1 上跑 36MHz两者的 BRR 计算基准不同。以 USART2 跑 4800bps 为例BRR 36 000 000 / 4800 7500写成 USART2-BRR 0x1D4C。如果分频配错成 72MHz同一个 BRR 值算出来就是 9600bps对端收到的全是乱码。烧录口用 PA13(SWDIO)、PA14(SWCLK) 的 SWD 模式。JTAG 在大数据量下载时失败率明显更高SWD 占用引脚少、高速下更稳调试器接四根线3.3V、GND、SWDIO、SWCLK就能用。2.3 ST7540 外围滤波网络与电流限制ST7540 到电力线之间不是直连中间有三级滤波顺序和作用不能随意调换。滤波级位置作用调整时的观察点发送有源滤波PA_OUT 之后抑制功放输出的谐波防止污染其他频段输出波形是否削顶发送无源滤波耦合变压器前阻抗匹配 进一步滤除带外分量耦合端电压幅度接收无源滤波RX_IN 之前窄带选频压低带外噪声弱信号下的接收误码率发送通路最终通过耦合变压器并到电力线上。接收通路经滤波后直接进 RX_IN芯片内部再做三次混频滤波在低信噪比条件下保证动态范围。24 脚的 CL 与 SVSS 之间接一个限流设定电阻这个电阻决定功放的最大输出电流——阻值取得太小轻载时波形失真取得太大重载时驱动不足。常用做法是先按典型值装上去用示波器看耦合端的波形边调边看不要一上来就按计算值赌。还有两处必须接地TEST1 直接接数字地TEST2 接模拟地(SVSS)。这两个脚悬空时芯片行为不确定表现是收发时好时坏很难查。2.4 TTL/RS232 电平转换与 I2C EEPROM 电路STM32 的 USART1 输出是 CMOS/TTL 电平PC 的串口是 RS232 电平两者之间用 MAX232 转换。MAX232 靠内部电荷泵把 5V 泵成 ±10V 左右需要外接 4 个 1μF 电容容值不足会直接导致通信距离变短或者完全不通。接线记住是交叉单片机 TX 接 MAX232 的 T1IN、对应输出 T1OUT 接 DB9 的 RXD单片机 RX 接 R1OUTR1IN 接 DB9 的 TXD。终端电表侧的数据存放在 EEPROM 里STM32 通过 I2C1(PB6/PB7) 读写。SDA 和 SCL 都是开漏输出必须外接上拉电阻4.7K 是常用值线长超过 20cm 可以降到 2.2K 提高上升沿速度。器件地址的低三位由 A0A2 引脚决定同一块板上挂多片时靠这三根线区分。/* I2C1 初始化100kHz 标准模式PB6SCLPB7SDA */ RCC-APB2ENR | RCC_APB2ENR_IOPBEN; RCC-APB1ENR | RCC_APB1ENR_I2C1EN; GPIOB-CRL ~(0xFF 24); GPIOB-CRL | (0xEE 24); /* PB6/PB7 复用开漏输出50MHz */ I2C1-CR2 36; /* APB1 36MHz单位 MHz */ I2C1-CCR 180; /* 标准模式36MHz/(2*100kHz) */ I2C1-TRISE 37; /* 36MHz * 1us 1 */ I2C1-CR1 | I2C_CR1_PE; /* 使能 I2C */这里有个隐蔽的坑APB1 一旦从 36MHz 改成 72MHzCCR 和 TRISE 必须同步重算否则 I2C 时序错乱表现为能写进去但读出来是 0xFF或者干脆卡在等待 ACK 的循环里。3. ST7540 寄存器配置与载波数据收发驱动3.1 REG_DATA 与 RxTx 的四种组合ST7540 靠两根控制线切换工作状态这两根线的组合决定了芯片此刻是收数据、发数据还是在读写内部寄存器。程序里第一件事就是把这张真值表封成函数不然后面到处直接操作 IO 口出错很难定位。REG_DATARxTx工作状态CLR/T 角色00数据传送发送时钟输入01数据接收恢复时钟输出11控制寄存器读出寄存器读时钟10控制寄存器写入寄存器写时钟状态切换后有一段 TCC 时间的空闲期数据线上不做任何事等芯片内部 PLL 稳定。很多发送时机不对导致丢首字节的问题就是把 TCC 等待省掉了。#define MODE_TX_DATA 0x00 /* REG_DATA0, RxTx0 */ #define MODE_RX_DATA 0x02 /* REG_DATA0, RxTx1 */ #define MODE_REG_READ 0x03 /* REG_DATA1, RxTx1 */ #define MODE_REG_WRITE 0x01 /* REG_DATA1, RxTx0 */ static void st7540_set_mode(uint8_t mode) { /* REG_DATA 接 PB0RxTx 接 PB1 */ GPIOB-BSRR (mode 0x01) ? GPIO_BSRR_BS0 : GPIO_BSRR_BR0; GPIOB-BSRR (mode 0x02) ? GPIO_BSRR_BS1 : GPIO_BSRR_BR1; if (mode 0x01) { /* 进入寄存器模式才需要时钟配合 */ delay_us(50); } }3.2 控制寄存器初始化频率、波特率、看门狗芯片上电后必须先写控制寄存器把发送频率、波特率、看门狗等参数配好再切到数据模式。寄存器写入是同步串行CLR/T 提供时钟TXD 上先送寄存器地址再送数据上升沿采样。初始化序列的顺序建议固定为先复位、再配频率、再配波特率、最后开看门狗。static void st7540_init(void) { st7540_set_mode(MODE_REG_WRITE); clr_t_low(); /* 拉低进入空闲等待 TCC */ delay_us(TCC_US); st7540_wr_reg(REG_CTRL_1, 0x00); /* 先清零控制位避免残留配置 */ st7540_wr_reg(REG_FREQ_SEL, FREQ_CHx); /* 选择载波通道8 档可选 */ st7540_wr_reg(REG_BAUD_SEL, BAUD_4800);/* 波特率必须与从机一致 */ st7540_wr_reg(REG_WD_CTRL, WD_EN); /* 使能看门狗掉线时自动复位输出 */ clr_t_high(); st7540_set_mode(MODE_RX_DATA); /* 初始化完先进接收态待命 */ }参数上有两个硬约束发送频率必须落在允许的载波频段内且同一台区内所有节点用同一档波特率两端必须完全一致ST7540 最高支持 4800bps超了直接不通信。看门狗建议开载波信道噪声重芯片偶尔会卡在某个状态看门狗能把发送通路复位回来。3.3 发送与接收UART 模式下的数据流UART/SPI 引脚拉高时RxD、TxD 走 UART 类型ST7540 作为通信主体提供 CLR/T 参考时钟拉低则走 SPI 类型。本设计用 UART 模式STM32 侧的 USART2 只需按普通串口收发不用自己造时钟。发送流程是切到 MODE_TX_DATA拉低 CLR/T 进空闲等 TCC然后往 USART2-DR 里写字节接收流程是切到 MODE_RX_DATACLR/T 由芯片输出恢复时钟RxD 上的数据在上升沿稳定STM32 用中断接收。接收态下芯片会关掉内部发送模块发送态下关掉接收模块这是它静态电流能压到 5mA 的原因不用手动去管。void st7540_send(const uint8_t *buf, uint16_t len) { st7540_set_mode(MODE_TX_DATA); clr_t_low(); delay_us(TCC_US); for (uint16_t i 0; i len; i) { while (!(USART2-SR USART_SR_TXE)); /* 等发送寄存器空 */ USART2-DR buf[i]; } while (!(USART2-SR USART_SR_TC)); /* 等最后一字节发完 */ st7540_set_mode(MODE_RX_DATA); /* 立刻切回接收准备应答 */ }发送完立刻切回接收态很关键。主从轮询下从机应答通常只有几毫秒的窗口如果发送后还停在发送态应答帧会直接丢掉表现为能发不能收。3.4 数据帧解析前导码、地址、命令与校验载波信道上电噪声大帧头必须有足够长的前导码让接收侧的窄带滤波器锁定。帧结构上建议固定字段顺序长度用显式字段而不是靠结束符判断。uint8_t frame_parse(const uint8_t *buf, uint16_t n, meter_frame_t *out) { uint16_t i 0; while (i 1 n !(buf[i] 0xAA buf[i1] 0x55)) i; /* 找帧头 */ if (i 6 n) return 0; /* 长度不够直接丢 */ out-addr buf[i2]; /* 电表地址 */ out-cmd buf[i3]; /* 命令码 */ out-len buf[i4]; /* 数据长度 */ if (out-len sizeof(out-data) || i 5 out-len 2 n) return 0; /* 越界保护别省这一步 */ for (uint8_t k 0; k out-len; k) out-data[k] buf[i5k]; uint16_t crc_rx buf[i5out-len] | (buf[i6out-len] 8); if (crc_rx ! crc16_modbus(buf[i2], out-len 3)) return 0; /* 校验不过交给上层重发 */ return 1; }解析函数里最不能省的是长度越界保护。载波信道误码是常态收到半截帧时如果直接按 len 拷贝会踩到缓冲区外面的内存现场表现是跑几个小时就死机比通信失败难查得多。4. PC 主节点协议与电表数据读写实现4.1 一对多轮询为什么不用侦听冲突系统拓扑是 PC 管理平台作主节点所有终端电表作从节点控制命令一律由主节点发出从节点只应答不主动发。这样一来就不存在多节点同时抢信道的问题也就不需要载波侦听多路访问那套机制——在电力线这种高噪声、高衰减的信道上做冲突检测本来就不可靠退回到主从轮询反而稳。代价是轮询周期。4800bps 下一帧 20 字节大约 40ms加上 TCC 等待和从机响应时间单节点一轮按 100ms 估128 户一个小区的完整轮询约 13 秒。对抄表这种一天一次的业务完全够用但别指望它做实时负荷监控。4.2 串口数据帧格式与 CRC16PC 与主板卡之间、主板卡与从板卡之间用同一套帧格式字段定义要一次定死后面扩功能只加命令码不动结构。字段长度说明前导码2 字节固定 0xAA 0x55地址1 字节0x00 为广播0x010xFE 为电表编号命令码1 字节0x01 读电量0x02 写参数0x03 校时长度1 字节后续数据域字节数数据域N 字节电量为 4 字节 BCD 或小端整数CRC162 字节Modbus 多项式 0xA001低字节在前uint16_t crc16_modbus(const uint8_t *p, uint16_t len) { uint16_t crc 0xFFFF; while (len--) { crc ^ *p; for (uint8_t i 0; i 8; i) crc (crc 0x01) ? (crc 1) ^ 0xA001 : (crc 1); } return crc; } /* 组帧返回整帧长度buf 由调用者保证足够大 */ uint16_t frame_build(uint8_t *buf, uint8_t addr, uint8_t cmd, const uint8_t *data, uint8_t len) { uint16_t i 0; buf[i] 0xAA; buf[i] 0x55; buf[i] addr; buf[i] cmd; buf[i] len; for (uint8_t k 0; k len; k) buf[i] data[k]; uint16_t crc crc16_modbus(buf[2], len 3); /* 从地址域开始算 */ buf[i] crc 0xFF; /* 低字节在前 */ buf[i] crc 8; return i; }CRC 的起算位置必须和解析端保持一致都从地址域算起把前导码排除在外。这一处对不上整个系统一帧都收不下来但单独测 CRC 函数又是对的很容易在两个模块之间来回甩锅。4.3 PC 侧串口收发与超时重发STM32 接 MAX232 的那路串口优先用中断接收配合一个环形缓冲和空闲超时状态机把不定长帧切出来。void USART1_IRQHandler(void) { if (USART1-SR USART_SR_RXNE) { uint8_t b USART1-DR; /* 读 DR 自动清 RXNE */ rx_ring_push(b); /* 入环形缓冲 */ last_rx_tick tick_ms; /* 刷新帧间超时计时 */ } if (USART1-SR USART_SR_ORE) { /* 溢出错误必须显式清 */ (void)USART1-DR; } }主循环里判断tick_ms - last_rx_tick 5就认为一帧结束。PC 侧发送命令后启动 200ms 超时超时未收到合法应答就重发连续三次失败把该节点标记为离线。这个重发次数不要设太大载波信道一次轮询本来就不长重发太多次会拖垮整个轮询周期。4.4 读电表数据从 EEPROM 取电量并回帧终端侧电表把电量存在 EEPROM 里主板卡收到读命令后按地址取出再回帧。读操作走标准 I2C 时序起始、器件地址写、内存地址、重启、器件地址读、连续读、非应答、停止。uint8_t ee_read(uint8_t dev, uint16_t off, uint8_t *buf, uint8_t len) { i2c_start(); if (!i2c_write((dev 1) | 0)) return 0; /* 器件地址 写 */ if (!i2c_write(off 8)) return 0; if (!i2c_write(off 0xFF)) return 0; i2c_start(); /* 重复起始不释放总线 */ if (!i2c_write((dev 1) | 1)) return 0; /* 器件地址 读 */ for (uint8_t i 0; i len; i) buf[i] i2c_read(i len - 1); /* 最后一字节回 NACK */ i2c_stop(); return 1; }注意最后一字节必须回非应答再发停止位回应答会让 EEPROM 继续输出下一字节把总线拉死。EEPROM 写周期约 5ms写完立刻读会拿到旧数据两次写之间要留够等待时间或者用应答轮询确认写完。4.5 写电表数据与掉电保护写电表参数比如费率、表号时单次写不超过 EEPROM 的页大小跨页要拆成多次。更重要的是顺序先把新数据写到一个备份区校验通过后再更新主区标志位。抄表系统最怕的是写一半掉电主区数据变成半新半旧电量对不上账。5. 联调顺序与串口、载波的故障定位联调不要一上来就把 PC、载波、电表全接上按链路分段验证出问题时才能定位到具体一段。第一步只接 STM32 和 PC用串口助手 4800-8-N-1 发固定字符串确认收发正常第二步示波器看 ST7540 的 CLR/T 有没有时钟输出判断芯片是否正常上电工作第三步两台板子之间用短线直接连 TX_OUT 和 RX_IN跳过电力线验证调制解调本身第四步接耦合变压器和电力线短距离通信第五步接电表终端跑完整轮询。常见故障的定位路径如下。现象高概率原因定位手段串口收到乱码波特率基准算错、晶振未起振量 OSC_OUT 有无 8MHz核对 APB 分频完全收不到数据TX/RX 未交叉、MAX232 电容不足短接 MAX232 两端做回环测试能发不能收发送后未及时切回接收态抓 RxTx 引脚电平变化时序通信时好时坏限流电阻取值不当、TEST 脚悬空示波器看耦合端波形有无削顶跨楼层就断跨配电变压器、三相耦合损失确认两端在同一台区同一相跑数小时死机帧解析越界、串口溢出未清加看门狗检查 ORE 标志处理有两个技巧值得单独说。一是做一条回环线把 ST7540 的 TX_OUT 直接短接到 RX_IN写一段自发自收的测试程序能把调制解调部分和电力线耦合部分彻底隔离开省掉大量来回换板子的时间。二是所有串口和 I2C 的等待循环都加超时退出载波信道噪声重硬件偶尔不响应是正常的卡死在 while 里等标志位比通信失败更难查——现场表现就是设备死机断电重启又好。最后调限流电阻时别按计算值一次到位。先在耦合端接示波器从小阻值慢慢往上调看波形从削顶变成完整正弦那个点再往上留一点余量。这个值跟实际线路阻抗相关换个台区可能要重调。本文还有配套的精品资源点击获取
返回列表