■ 显示屏

屏幕资料和参考资料
显示屏代码共享平台 SSD1306驱动器

■ 01. 正点原子资料下载中心

正点原子资料下载中心

0.96寸OLED模块128*64 http://www.openedv.com/docs/modules/lcd/0.96-OLED-12864.html

■ 02. SSD1306驱动器

显示屏代码共享平台 SSD1306驱动器

■ 03. OLED多级菜单资料V3.2

OLED多级菜单资料

■ 04. 1.8寸TFT LCD128X160 ST7735S SPI串口屏驱动示例

链接:https://pan.baidu.com/s/10G6apA8plumMz1A8FLoGhg
提取码:1111

■ 05. 元芯电子GD32F303VGT6开发板STM32评估核心板ARM最小系统VCT6例程

CAN
SPi  W25Q32
SDIO
W5500芯片 + HR911105A网络 SPI 驱动
LCD模块 ILI19341 触摸屏  SPI驱动 XPT2046
EEPROM  芯片使用AT24C02用于验证IIC协议   

开源链接:https://pan.baidu.com/s/1-eRv9octW-Wmv85QZ9L3Rg
提取码:aytk
视频教程:https://space.bilibili.com/621871525

开源资料链接:https://pan.baidu.com/s/1fSEi0KT6yzQ5FwUtIYiNlQ
提取码:b8bv
视频教程:https://space.bilibili.com/621871525

■ 06. 元芯ST7735s显示屏TFT模块IPS彩屏0.96寸四线SPI LCD显示屏80x160

GITEE: https://gitee.com/meta-mcu/st7735s-st7735-096-inch-tft
GITHUB: https://github.com/META-MCU/st7735s-tft-0.96inch
视频教程:https://www.bilibili.com/video/BV11P4y1q7pL

■ SMT32

■ 01.【桥边姑娘】SMT32 ADC+FFT+OLED 音乐频谱显示

代码链接:

■ 02. SMT32-uart 空闲中断(USART_IT_IDLE)

当发送完一包数据后触发空闲中断提示用户去解析数据包
适用于Modebus-RTU解包

typedef struct _UART4_BUF
{
    uint8_t	 cache[BUFFER_MAX];
    int 	 size;
	  int      rxdong; //读完成标志
}UART4_BUF;	
UART4_BUF gUart4_buff;

volatile int rx_count=0;
void UART4_IRQHandler(void)
{
		uint8_t temp;
    if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)  //接收中断,可以扩展来控制
    {
		gUart4_buff.cache[rx_count++] = USART_ReceiveData(UART4);

		if (rx_count > (BUFFER_MAX - 1)) {
			rx_count=0;
		}
		gUart4_buff.rxdong=0;
		USART_ClearITPendingBit(UART4, USART_IT_RXNE);
    }
    if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  //模块空闲
    {
		temp=UART4->SR; //先读SR,再读DR才能完成idle中断的清零,否则一直进入中断。
		temp=UART4->DR;
		gUart4_buff.size = rx_count;
		rx_count=0;
		gUart4_buff.rxdong = 1;   //读完成中断标识,在其他地方读取这个标识进行数据解析。
    }
}

注意事项:
调用库函数USART_ClearITPendingBit(DEBUG_USARTx, USART_IT_IDLE);是不会清除空闲中断标志位的。应该采用42-43两条语句实现,否则会一直进入中断函数。
在这里插入图片描述

■ 03. 基于江科大的OLED多级菜单教学

链接:https://pan.baidu.com/s/1efxv9l3XWk9oGQqwQU-rXg?pwd=7544
提取码:7544

■ 04. MPU6050

野火STM32F103标准外设库(SPL)开发教学视频【全集】

■ 05. Modebus-RTU-Slave(从机代码)

采用中断进行接收数据,开启空闲中断,当接收完一包数据后触发空闲中断,主程序去解包处理
定时100ms 发送数据进行解包是OK的

■ 001. rs485.h

#ifndef _rs485_H
#define _rs485_H

#include "sys.h"
#include "stdio.h"
#include "string.h"

#define        BUFFER_MAX 256      //数组缓存大小
typedef struct _UART4_BUF
{
    uint8_t	 cache[BUFFER_MAX];
    int 	 size;
	int      rxdong; //读完成标志
}UART4_BUF;	


extern u8 RS485_Flag;
extern UART4_BUF gUart4_buff;

//模式控制
#define RS485_TX_EN		PBout(8)	//485模式控制.0,接收;1,发送.

														 
void RS485_Init(u32 bound);
void RS485_ClearBuf(void);
void RS485_SendStr(uint8_t*SendBuf);
void RS485_SendData(uint8_t*buf,int len);

#endif

■ 002. rs485.c

#include "rs485.h"
#include "delay.h"
#include "usart.h"

UART4_BUF 	gUart4_buff;


/*******************************************************************************
* 函 数 名         : RS485_Init
* 函数功能		   : USART2初始化函数
* 输    入         : bound:波特率
* 输    出         : 无
*******************************************************************************/
void RS485_Init(u32 bound)
{
    GPIO_InitTypeDef 	GPIO_InitStructure;
    USART_InitTypeDef 	USART_InitStructure;
    NVIC_InitTypeDef 	NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);//使能UART4时钟

    /*  配置GPIO的模式和IO口 */
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;		//TX-485	//串口输出PC10
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOC,&GPIO_InitStructure);		     /* 初始化串口输入IO */

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;	//RX-485	//串口输入PC11
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;	    //模拟输入
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOC,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;	//CS-485
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;	   //推挽输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    //USART4 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(UART4, &USART_InitStructure); //初始化串口2

    USART_Cmd(UART4, ENABLE);  //使能串口 4
    USART_ClearFlag(UART4, USART_FLAG_TC);
    USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启接受中断
    USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);

    //Uart4 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

    RS485_TX_EN=0; //接收
}

void RS485_SendStr(uint8_t* SendBuf)    //串口4打印数据
{
	RS485_TX_EN=1; //发送
    while(*SendBuf)
    {
        UART4->DR = (u8)*SendBuf;
		while((UART4->SR & 0X40)==0);   //等待发送完成
        SendBuf++;
    }
	RS485_TX_EN=0; //接收
}

void RS485_SendData(uint8_t* buf,int len) //串口4打印数据
{
    int i=0;
	RS485_TX_EN=1; //发送
    for(i=0; i<len; i++)
    {
        UART4->DR = (u8)buf[i];
		while((UART4->SR & 0X40)==0);   //等待发送完成
    }
	
	RS485_TX_EN=0; //接收
}

void RS485_ClearBuf()
{
    gUart4_buff.size = 0;
    memset(gUart4_buff.cache,0,sizeof(gUart4_buff.cache));
}


volatile int rx_count=0;
void UART4_IRQHandler(void)
{
	uint8_t temp;
    if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)  //接收中断,可以扩展来控制
    {
		gUart4_buff.cache[rx_count++] = USART_ReceiveData(UART4);

		if (rx_count > (BUFFER_MAX - 1)) {
			rx_count=0;
		}
		gUart4_buff.rxdong=0;
		USART_ClearITPendingBit(UART4, USART_IT_RXNE);
    }
    if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  //模块空闲
    {
		temp=UART4->SR; //先读SR,再读DR才能完成idle中断的清零,否则一直进入中断。
		temp=UART4->DR;
		gUart4_buff.size = rx_count;
		rx_count=0;
		gUart4_buff.rxdong = 1;
    }
}

■ 003. modbus_RTU.c

#include "modebus_RTU.h"


/* CRC高字节表 */
const static uint8_t crctableh[] =
{
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
   0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
   0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40
};
/* CRC低字节表 */
const static uint8_t crctablel[] =
{
   0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
   0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
   0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
   0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
   0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
   0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
   0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
   0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
   0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
   0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
   0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
   0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
   0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
   0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
   0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
   0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
   0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
   0x40
};

//CRC查表函数,返回CRC-16校验码低字节在前
uint16_t modbus_crc16(uint8_t *ptr, uint16_t len)
{
   uint8_t crch = 0xFF;
   uint8_t crcl = 0xFF;
   uint16_t index;
   while (len--)
   {
       index = crcl ^ *ptr++;
       crcl = crch ^ crctableh[index];
       crch = crctablel[index];
   }
   return ((uint16_t)(crch | crcl << 8));
}

■ 004. modbus_RTU.h

#ifndef __MODEBUS_RTU_H
#define __MODEBUS_RTU_H

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "delay.h"


//定义功能码
#define MODBUS_FUNC_READ_COIL_REG           0x01     //读线圈
#define MODBUS_FUNC_READ_DIS_INPUT_REG      0x02     //读离散输入
#define MODBUS_FUNC_READ_HOLD_REG           0x03     //读保持寄存器
#define MODBUS_FUNC_READ_INPUT_REG          0x04     //读输入寄存器
#define MODBUS_FUNC_WRITE_SIN_COIL_REG      0x05     //写单个线圈
#define MODBUS_FUNC_WRITE_SIN_HOLD_REG      0x06     //写单个保持寄存器
#define MODBUS_FUNC_WRITE_MULT_COIL_REG     0x0F     //写多个线圈
#define MODBUS_FUNC_WRITE_MULT_HOLD_REG     0x10     //写多个保持寄存器

uint16_t modbus_crc16(uint8_t *ptr, uint16_t len);

#endif

■ 005. modebus_RTU_Slave.c

#include "modebus_RTU_Slave.h"
#include "rs485.h"

modbus_slave_t  gRTUslave;
UART4_BUF g_wxcache;

#define  REG_HOLDING_COUNT    1024
uint16_t modbus_holding_regs[REG_HOLDING_COUNT]; //寄存器存储区(用户可读写)
	

uint8_t ModbusRtu_Slave_Init()
{
	ModbusRtuSlaveInit(&gRTUslave,0x0A,&gUart4_buff,&g_wxcache);
    return 1;
}


uint8_t ModbusRtuSlaveInit(modbus_slave_t* slave,
								uint8_t   slaveAdd,
								UART4_BUF* rxcache,
								UART4_BUF* wxcache)
{
	slave->slaveID  = slaveAdd;
	slave->rx_cache = rxcache;
	slave->wx_cache = wxcache;

    RS485_Init(9600);
    RS485_SendStr((uint8_t*)"RS485 Init Successful\r\n");
    return 1;
}

void Modbus_slave_task()
{
	if(gRTUslave.rx_cache->rxdong){
		Modbus_slave_parse_frame(&gRTUslave);
		gRTUslave.rx_cache->rxdong=0;
	}
//	else
//	{
//		printf("++++++++++++++=%d\r\n",gRTUslave.rx_cache->size);
//	}
}

void Modbus_slave_parse_frame(modbus_slave_t* modbusSlave)
{
	uint16_t crc_calc=0;
	uint16_t crc_recv=0;

	UART4_BUF* prx_cache = modbusSlave->rx_cache;

    if(prx_cache->size < 6)
		return;   //最小帧长

	crc_calc = modbus_crc16(prx_cache->cache, prx_cache->size - 2);
	crc_recv = (prx_cache->cache[prx_cache->size-2] << 8) | prx_cache->cache[prx_cache->size-1];

	if(crc_calc == crc_recv) //CRC检验成功 开始分析包
	{
		if(prx_cache->cache[0] == modbusSlave->slaveID)  //检查地址是否时自己的地址
		{
			switch(prx_cache->cache[1]){   	     //modbus功能码
			case MODBUS_FUNC_READ_COIL_REG: 	 //0x01 读线圈
				break;
			case MODBUS_FUNC_READ_DIS_INPUT_REG: //0x02 读离散输入
				break;
			case MODBUS_FUNC_READ_HOLD_REG: 	 //0x03 读保持寄存器
				Modbus_Func03(modbusSlave);
				break;
			case MODBUS_FUNC_READ_INPUT_REG:	 //0x04 读输入寄存器
				
				break;
			case MODBUS_FUNC_WRITE_SIN_COIL_REG: //0x05 写单个线圈
				
				break;
			case MODBUS_FUNC_WRITE_SIN_HOLD_REG: //0x06 写单个保持寄存器
				Modbus_Func06(modbusSlave);
				break;
			case MODBUS_FUNC_WRITE_MULT_COIL_REG://0x0F 写多个线圈
				
				break;
			case MODBUS_FUNC_WRITE_MULT_HOLD_REG://0x10 写多个保持寄存器
				Modbus_Func10(modbusSlave);
				break;		 
			}
		 }
		 else if(prx_cache->cache[0] == 0) //广播地址不予回应
		 {
		    printf("add = 0,,%d\r\n",prx_cache->cache[0]);
		 }
	}
}

void Modbus_Func03(modbus_slave_t* modbusSlave)
{
    u16 Regadd,Reglen,crc;
	u8 i,j;	
	UART4_BUF* rx_cache = modbusSlave->rx_cache;
	UART4_BUF* wx_cache = modbusSlave->wx_cache;
	
	//得到要读取寄存器的首地址
	Regadd = rx_cache->cache[2]*256 + rx_cache->cache[3];
	//得到要读取寄存器的数据长度
	Reglen = rx_cache->cache[4]*256 + rx_cache->cache[5];
	
	//发送回应数据包
	i = 0;
	wx_cache->cache[i++] = modbusSlave->slaveID;    //发送本机设备地址
	wx_cache->cache[i++] = 0x03;              		//发送功能码
    wx_cache->cache[i++] = ((Reglen*2)%256);  		//返回字节个数

	for(j=0;j<Reglen;j++)                      		//返回数据
	{
		wx_cache->cache[i++] = modbus_holding_regs[Regadd+j]/256;
		wx_cache->cache[i++] = modbus_holding_regs[Regadd+j]%256;
	}
	crc = modbus_crc16(wx_cache->cache,i);    //计算要返回数据的CRC
	wx_cache->cache[i++] = crc/256;
	wx_cache->cache[i++] = crc%256;
	
	wx_cache->size=i;
	RS485_SendData(wx_cache->cache,wx_cache->size);
}

void Modbus_Func06(modbus_slave_t* modbusSlave)
{
	u16 Regadd;
	u16 val;
	u16 i=0,crc=0;

	UART4_BUF* rx_cache = modbusSlave->rx_cache;
	UART4_BUF* wx_cache = modbusSlave->wx_cache;

	Regadd = rx_cache->cache[2]*256 + rx_cache->cache[3];  //寄存器地址
	val    = rx_cache->cache[4]*256 + rx_cache->cache[5];  //修改后的值
	modbus_holding_regs[Regadd]=val;  	//修改本设备相应的寄

	//以下为回应主机
	wx_cache->cache[i++] = modbusSlave->slaveID; //本设备地址
	wx_cache->cache[i++] = 0x06;        		 //功能码 
	wx_cache->cache[i++] = Regadd/256;
	wx_cache->cache[i++] = Regadd%256;
	wx_cache->cache[i++] = val/256;
	wx_cache->cache[i++] = val%256;
	crc = modbus_crc16(wx_cache->cache,i);
	wx_cache->cache[i++] = crc/256;
	wx_cache->cache[i++] = crc%256;

	wx_cache->size=i;
	RS485_SendData(wx_cache->cache,wx_cache->size);
}

void Modbus_Func10(modbus_slave_t* modbusSlave)
{
	u16 Regadd,RegNum;
	u16 bySize,RegNumMax;
	u16 i=0,f=0,crc=0;

	UART4_BUF* rx_cache = modbusSlave->rx_cache;
	UART4_BUF* wx_cache = modbusSlave->wx_cache;

	Regadd = rx_cache->cache[2]*256 + rx_cache->cache[3];  //寄存器地址
	RegNum = rx_cache->cache[4]*256 + rx_cache->cache[5];  //寄存器数量
	bySize = rx_cache->cache[6]; //字节数
	
	RegNumMax = bySize/2;
	for(f=0;f<RegNumMax;f++)
	{
		//修改本设备相应的寄存器
		modbus_holding_regs[Regadd+f] = rx_cache->cache[6+f]*256 + rx_cache->cache[6+f+1];
	}

	//以下为回应主机
	wx_cache->cache[i++] = modbusSlave->slaveID; //本设备地址
	wx_cache->cache[i++] = 0x10;        		 //功能码 
	wx_cache->cache[i++] = Regadd/256;       //起始地址
	wx_cache->cache[i++] = Regadd%256;
	wx_cache->cache[i++] = RegNum/256;       //寄存器数量
	wx_cache->cache[i++] = RegNum%256;
	crc = modbus_crc16(wx_cache->cache,i);
	wx_cache->cache[i++] = crc/256;
	wx_cache->cache[i++] = crc%256;

	wx_cache->size=i;
	RS485_SendData(wx_cache->cache,wx_cache->size);
}


■ 006. modebus_RTU_Slave.h

#ifndef __MODEBUS_RTU_SLAVE_H
#define __MODEBUS_RTU_SLAVE_H

#include "modebus_RTU.h"
#include "rs485.h"


typedef struct _modbus_slave_t {
    uint8_t 	slaveID;
	UART4_BUF* 	rx_cache;  //接收缓冲区
	UART4_BUF* 	wx_cache;  //发送缓冲区


	uint32_t last_byte_time;  // 最后接收字节的时间(ms)

    uint8_t debug;
    uint8_t error_recovery;
    uint8_t quirks;
}modbus_slave_t;


#define MODBUS_MASTER_ADDRESS     0x01  //主机地址为0x01
#define MODBUS_SLAVE1_ADDRESS     0x02  //从机地址为0x02

uint8_t ModbusRtu_Slave_Init(void);
uint8_t ModbusRtuSlaveInit(modbus_slave_t* slave,uint8_t slaveAdd,
							UART4_BUF* rxcache,
							UART4_BUF* wxcache);
void Modbus_slave_task(void);    //主循环调用
void Modbus_slave_parse_frame(modbus_slave_t* modbusSlave);

void Modbus_Func03(modbus_slave_t* modbusSlave);
void Modbus_Func06(modbus_slave_t* modbusSlave);
void Modbus_Func10(modbus_slave_t* modbusSlave);

#endif
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐