RS485总线是一种常见的(Recommended Standard)串行总线标准(485是它的标识号),采用平衡发送与差分接收的方式,因此具有抑制共模干扰的能力。CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络,属于CSMA(多路载波侦听)/CD(冲突检测)+AMP(基于消息优先级的冲突检测)总线并具备错误检测能力。

CAN总线起初用于实现汽车内ECU(Electronic Control Unit)之间可靠的通信,后因其简单实用可靠等特点,而广泛应用于工业自动化、船舶、医疗等其它领域。串口是工业自动化系统中非常重要的通讯方式,在工业自动化通讯系统始终占据非常重要的地位。因为485具有通信距离远,易布线等优点,常用于工业自动化智能终端,后因其技术特点,大部分的仪器仪表以及众多一主多从通信架构的产品都采用了这种通信方式。

本篇文章介绍了使用STM32+MAX485实现485通信以及使用STM32+TJA1004实现CAN通信的方法,并补充说明了CAN通信采样点和负载率的公式计算说明。

文章目录

概念说明

实现原理

嵌入式程序

485通信

CAN通信

CAN参数补充说明


概念说明

  • 总线:总线(Bus)是一组能为多个部件分时共享的公共信息传送线路。分时和共享是总线的两个特点。计算机组成中总线分为地址总线、数据总线以及控制总线,他们挂接的计算机各功能部件(CPU,内存,显卡,硬盘),而我们文章提到的总线是各独立的智能硬件之间产品的串行通信方式,如果您能把多个产品(网关+n个终端)理解成一个智能产品系统,那么就不能理解为什么称这种通信方式为总线。
  • 差分信号:单端信号指的是用一个线传输的信号,以地为参考点,这样测量信号的精确值依赖系统内地的一致性,信号源和信号接收器距离越远,他们局部地的电压值之间有差异的可能性就越大。差分信号指的是用两根线传输信号,信号值是两个导体间的电压差,假如两条信号都收到同样的(同向、等幅度)的干扰信号,由于接收端是对接收的两条线信号进行减法处理,因此干扰信号会被基本抵消。
  • CSMA/CD:CSMA协议要求站点在发送数据之前先监听信道。如果信道空闲,站点就可以发送数据;如果信道忙,则站点不能发送数据。在早期的CSMA传输方式中,由于信道传播时延的存在,即使通信双方的站点,都没有侦听到载波信号,在发送数据时仍可能会发生冲突。如果发生冲突,信道上可以检测到超过发送站点本身发送的载波信号幅度的电磁波,由此判断出冲突的存在。一旦检测到冲突,发送站点就立即停止发送,并向总线上发一串阻塞信号,用以通知总线上通信的对方站点,快速地终止被破坏的帧,然后进行新一轮的总线竞争。
  • 收发器:收发器的主要功能是将CAN或UART控制器的TTL收发信号转换成CAN总线的单工差分信号,本例中485的收发器为MAX485,它的输入信号除了TX/RX,还有一个控制方向的引脚来控制当前芯片工作在收还是发模式,CAN的收发器为TJA1004。整体总线通信架构如下图:


实现原理

嵌入式程序跑在STM32平台上,正确配置UART以及CAN控制器的通信参数(速率帧格式等),正确驱动收发器(部分486收发器需要控制方向,CAN控制器有唤醒帧功能,需要进行正确操作)。然后嵌入式程序即可通过控制器进行数据的收发,下图是实现原理:


嵌入式程序

485/CAN通信的嵌入式程序比较简单,基本分为两个部分:

  1. 控制器的初始化
  2. 收发器操作与数据的收发

流程架构图如下:


485通信

串口控制器的初始化包括:

  1. 开启串口控制器以及相应IO口时钟
  2. 初始化IO口以及配置串口中断
  3. 配置串口通信参数

下面是相关的接口代码(已经增加中文注释帮助理解),代码支持使用不同串口控制器来实现484通信:

//时钟初始化
void uart_RCC(USART_TypeDef* USARTx,uint32_t RCC_APB_Tx,uint32_t RCC_APB_Rx)
{//相对应串口时钟if(USARTx == USART1)RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);else if(USARTx == USART2)RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);else if(USARTx == USART3)RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);else if(USARTx == UART4)RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //相对串口的TxRx GPIO时钟RCC_APB2PeriphClockCmd(RCC_APB_Tx|RCC_APB_Rx,ENABLE);
}
//GPIO初始化
void uart_GPIO(GPIO_TypeDef* TX_GpioPort,uint16_t TX_GpioPin,GPIO_TypeDef* RX_GpioPort,uint16_t RX_GpioPin,GPIO_TypeDef* Dir_GpioPort,uint16_t Dir_GpioPin)
{GPIO_InitTypeDef GPIO_InitStructure;//USARTx_TXGPIO_InitStructure.GPIO_Pin = TX_GpioPin;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽GPIO_Init(TX_GpioPort, &GPIO_InitStructure);//USARTx_RXGPIO_InitStructure.GPIO_Pin = RX_GpioPin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入GPIO_Init(RX_GpioPort, &GPIO_InitStructure);//directionGPIO_InitStructure.GPIO_Pin = Dir_GpioPin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_Init(Dir_GpioPort, &GPIO_InitStructure);
}
//串口中断配置
void uart_NVIC(uint8_t NVIC_IRQChannel,uint8_t NVIC_IRQChannelPreemptionPriority,uint8_t NVIC_IRQChannelSubPriority)
{NVIC_InitTypeDef NVIC_InitStructure;//设置NVIC优先级分组为2NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//串口接收中断打开 NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQChannel;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_IRQChannelPreemptionPriority;NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_IRQChannelSubPriority;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}
//
///华丽的分割线
///
//串口初始化
uint8 u8_drv_uart_Init(USART_TypeDef* USARTx)
{if(USARTx == USART1){uart_RCC(USART1,D_UART1_TX_RCC,D_UART1_RX_RCC); //重映射//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//开启端口B和复用时钟功能//GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);//使能端口重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启端口B和复用时钟功能uart_GPIO(D_UART1_TX_PORT,D_UART1_TX_PIN,D_UART1_RX_PORT,D_UART1_RX_PIN);v_drv_uart_NVIC(USART1_IRQn,D_USART1_IRQn_PreemptionPriority,D_USART1_IRQn_SubPriority);}else if(USARTx == USART2){uart_RCC(USART2,D_UART2_TX_RCC,D_UART2_RX_RCC); uart_GPIO(D_UART2_TX_PORT,D_UART2_TX_PIN,D_UART2_RX_PORT,D_UART2_RX_PIN);v_drv_uart_NVIC(USART2_IRQn,D_USART2_IRQn_PreemptionPriority,D_USART2_IRQn_SubPriority);}else if(USARTx == USART3){uart_RCC(USART3,D_UART3_TX_RCC,D_UART3_RX_RCC);   uart_GPIO(D_UART3_TX_PORT,D_UART3_TX_PIN,D_UART3_RX_PORT,D_UART3_RX_PIN);v_drv_uart_NVIC(USART3_IRQn,D_USART3_IRQn_PreemptionPriority,D_USART3_IRQn_SubPriority);}else if(USARTx == UART4){uart_RCC(UART4,D_UART4_TX_RCC,D_UART4_RX_RCC); uart_GPIO(D_UART4_TX_PORT,D_UART4_TX_PIN,D_UART4_RX_PORT,D_UART4_RX_PIN);uart_NVIC(UART4_IRQn,D_USART4_IRQn_PreemptionPriority,D_USART4_IRQn_SubPriority);}else{}
}
//串口发送
void uart_Send(USART_TypeDef* USARTx,char *pc_data,uint8_t u8_len)
{uint8_t i = 0;GPIO_SetBits(Dir_GpioPort, Dir_GpioPin);//收发器发送模式for(i=0;i<u8_len;i++){USART_SendData(USARTx, *pc_data); while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} pc_data++;}GPIO_ResetBits(Dir_GpioPort, Dir_GpioPin);//收发器接收模式
}

下面是利用485总线发送“Hello world”以及接收中断函数,中断函数只提供了UART1,其余串口逻辑一致。代码如下:

//485通信初始化接口
uint8_t RS485_InitSerial(USART_TypeDef* USARTx,tsUart *psUart)
{u8_drv_uart_Init(USARTx);v_drv_uart_Configuration(USARTx, psUart->u32Uartbaud, psUart->u8WordLength, psUart->u8StopBits, psUart->u8Parity);uart_Send(USARTx,"Hello world",11);return 1;
}
//串口1的接收中断
void USART1_IRQHandler(void)
{unsigned char Temp=0;if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)  {   //OverRun Error interruptUSART_ReceiveData(USART1); }   if(USART_GetFlagStatus(USART1, USART_FLAG_NE) != RESET) {//Noise Error interrupt }   if(USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET) {//Framing Error interrupt }   if(USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET) {//Parity Error interrupt }///if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){Temp=USART_ReceiveData(USART1);//添加处理字符的代码USART_ClearITPendingBit(USART1,USART_IT_RXNE);}
}

CAN通信

CAN控制器的初始化同样包括了中断,IO口初始化,以及发送帧的实现,下面是这部分代码,以提供了中文注释帮助大家理解:

//延时函数
void _NOP_(int x)
{int j=0;for(j=0;j<x;j++){;  }
}
//中断初始化函数
static void CAN_NVIC_Configuration(uint32 canx)
{NVIC_InitTypeDef NVIC_InitStructure;/* Configure the NVIC Preemption Priority Bits */  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);#ifdef  VECT_TAB_RAM  /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else  /* VECT_TAB_FLASH  *//* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   #endifNVIC_InitStructure.NVIC_IRQChannel = can[canx].rx0_irq;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//0;//1;if (canx == 0)NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;elseNVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = can[canx].sce_irq;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);#ifdef CAN_TX_INT_ENABLE    NVIC_InitStructure.NVIC_IRQChannel = can[canx].tx_irq;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
#endif
}
//CAN IO口初始化
tatic void CAN_PinInit(uint32 canx)
{GPIO_InitTypeDef  GPIO_InitStructure;/* Configure CAN pin: RX */RCC_APB2PeriphClockCmd(can[canx].gpio_rx.rccx | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin = can[canx].gpio_rx.index;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(can[canx].gpio_rx.channel, &GPIO_InitStructure);/* Configure CAN pin: TX */RCC_APB2PeriphClockCmd(can[canx].gpio_tx.rccx | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin = can[canx].gpio_tx.index;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Mode_AF_PP;//GPIO_Mode_Out_PP;GPIO_Init(can[canx].gpio_tx.channel, &GPIO_InitStructure);/* Configure CAN pin: STB */RCC_APB2PeriphClockCmd(can[canx].gpio_stb.rccx | RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStructure.GPIO_Pin = can[canx].gpio_stb.index;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(can[canx].gpio_stb.channel, &GPIO_InitStructure);
}
//CAN控制器配置
static int CAN_Configuration(uint32 canx)
{CAN_InitTypeDef        CAN_InitStructure;CAN_FilterInitTypeDef  CAN_FilterInitStructure;if(canx==0){RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);}else{RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);}// CAN register init CAN_DeInit(can[canx].canx);CAN_StructInit(&CAN_InitStructure);// CAN cell init CAN_InitStructure.CAN_TTCM=DISABLE;//禁止时间触发通信模式CAN_InitStructure.CAN_ABOM=ENABLE;CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过清除sleep位唤醒CAN_InitStructure.CAN_NART=DISABLE;//报文自动重传CAN_InitStructure.CAN_RFLM=DISABLE;//接收溢出时,FIFO未锁定CAN_InitStructure.CAN_TXFP=DISABLE;//发送的优先级由标识符的大小决定CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//正常模式//设置CAN的通信速率为50kbps,采样点百分之八十CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;CAN_InitStructure.CAN_BS1=CAN_BS1_14tq;CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;CAN_InitStructure.CAN_Prescaler=4;if (CAN_Init(can[canx].canx, &CAN_InitStructure) == 0)return -1;// CAN filter init if (canx == 0)CAN_FilterInitStructure.CAN_FilterNumber=0;elseCAN_FilterInitStructure.CAN_FilterNumber=14;CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//CAN_FilterScale_16bit; //32bitCAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;   //时能过滤器CAN_FilterInit(&CAN_FilterInitStructure);CAN_ITConfig(can[canx].canx, CAN_IT_FMP0, ENABLE);CAN_ITConfig(can[canx].canx, CAN_IT_ERR, ENABLE);
#ifdef CAN_TX_INT_ENABLE        CAN_ITConfig(can[canx].canx, CAN_IT_TME, ENABLE);
#endifcan[canx].state |= INIT_COMPLETE;return 0;
}
//CAN数据帧实现
static unsigned char _CAN_SendData(uint32 canx, uint32 StdId, uint8 DLC, uint8 * Data)
{uint16 i;uint16 count = 0;CanTxMsg TxMessage;unsigned char TransmitMailbox;if((DLC-0)==0){return 1;}TxMessage.StdId=StdId;     //标准标识符TxMessage.ExtId=StdId; TxMessage.RTR=CAN_RTR_DATA;TxMessage.IDE=CAN_ID_EXT/*CAN_ID_STD*/;TxMessage.DLC=DLC;      //数据长度if(DLC>8){TxMessage.Data[0]=0xFF;}else{for(i=0;i<DLC;i++){TxMessage.Data[i]=Data[i];}}
#ifdef CAN_TX_INT_ENABLE
waiting:if (canx == 0) {if (sem_value_can1 > 0) {sem_value_can1--;} else {_NOP_(1);goto waiting;}}
#ifdef STM32F10X_CL     else {if (sem_value_can2 > 0) {sem_value_can2--;} else {_NOP_(1);goto waiting;}}
#endifTransmitMailbox=CAN_Transmit(can[canx].canx,&TxMessage);
#elsecount = 0;
retry:      TransmitMailbox=CAN_Transmit(can[canx].canx,&TxMessage);if (TransmitMailbox == CAN_TxStatus_NoMailBox) {count++;if (count > MAXTRYCOUNT){   //can_init(canx);goto out;}goto retry;}i = 0xFFF;do {_NOP_(1);} while((CAN_TransmitStatus(can[canx].canx, TransmitMailbox) != CANTXOK) && (--i));count = 0;if (i <= 0x01){count++;if (count > MAXTRYCOUNT){ //can_init(canx);goto out;}goto retry;}//return 0;elsereturn 1;
out:return 0;
#endif
}

下面的代码按定义参数正确配置了CAN控制器,并封装了供上层调用的发送接口,我还附上了CAN接收中断代码:

static uint8 u8CanSndId[2];
static struct can_info can[CAN_NUM] = {{RCC_APB1Periph_CAN1,19, 20, 21/*CAN1_TX_IRQn, CAN1_RX0_IRQn, CAN1_RX1_IRQn*/,22/*CAN1_SCE_IRQn*/, {RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_11},{RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_12}, {RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_8},CAN1,},{RCC_APB1Periph_CAN2,63, 64, 65/*CAN2_TX_IRQn, CAN2_RX0_IRQn, CAN2_RX1_IRQn*/,66/*CAN2_SCE_IRQn*/,{RCC_APB2Periph_GPIOB, GPIOB, GPIO_Pin_12},{RCC_APB2Periph_GPIOB, GPIOB, GPIO_Pin_13},{RCC_APB2Periph_GPIOB, GPIOB, GPIO_Pin_11},CAN2,},};//can通信参数//CAN初始化
void can_init(uint32 canx)
{   canx -= 1;CAN_PinInit(canx);                                   //Configurate the GPIOCAN_NVIC_Configuration(canx);                     //Configurate the NVICCAN_Configuration(canx);
}
//CAN发送数据
unsigned char CAN_SendData(uint32 canx, uint16 addr, uint16 Length, uint8 *Data)
{unsigned int SendNumber=0;unsigned int i=0;unsigned int res=0;uint32 ExtId;SendNumber=Length/8;canx -= 1;//---------------------------u8CanSndId[canx]++;if(u8CanSndId[canx] >= 255){u8CanSndId[canx] = 1;}//---------------------------ExtId =(0x10000000 | addr) + (u8CanSndId[canx]<<16);res=_CAN_SendData(canx, ExtId, 8, Data);if(res!=1){return 0;}for(i=1; i<SendNumber; i++){//---------------------------u8CanSndId[canx]++;if(u8CanSndId[canx] >= 255){u8CanSndId[canx] = 1;}//---------------------------//ExtId = addr;ExtId = addr + (u8CanSndId[canx]<<16);res=_CAN_SendData(canx, ExtId,8,Data+8*i);
#ifndef CAN_TX_INT_ENABLE   if(res!=1){return 8*i;}
#endif}//---------------------------u8CanSndId[canx]++;if(u8CanSndId[canx] >= 255){u8CanSndId[canx] = 1;}//---------------------------//ExtId = addr;ExtId = addr + (u8CanSndId[canx]<<16);res=_CAN_SendData(canx, ExtId, Length-(SendNumber*8), Data+8*i);
#ifndef CAN_TX_INT_ENABLE   if(res!=1){return 8*i;}
#endifreturn Length;
}
//CAN1接收中断
void CAN1_RX0_IRQHandler(void)
{uint8 i=0;uint8 u8QueueIndex = 0;uint16 u16Address = 0;uint32 u32CanRevId = 0;CanRxMsg RxMessage;CAN_Receive(CAN1,CAN_FIFO0, &RxMessage);s_app_can_paraD1.u8Mode = 1;s_app_can_paraD1.u32WaitReceiveFinishCount = sDeviceConfig.sCan1.u32WaitReceiveFinishCount; //-------------------------------------------------------------u32CanRevId = RxMessage.ExtId;//-------------------------------------------------------------u8QueueIndex = u8_app_can_FindQueueIndexD1(u32CanRevId);if(u8QueueIndex == 0){return;}  else if(u8QueueIndex>=CANDQUEUENUM-1){return;}else if(u8QueueIndex == 0xff){  return;}//-------------------------------------------------------------for(i=0;i<RxMessage.DLC;i++){ //CAN接收处理函数(RxMessage.Data[i],u8QueueIndex);}s_app_can_paraD1.u8Mode = 0;
}

CAN参数补充说明

  • CAN采样点:CAN发送的每一位数据(0或者1)维持的时间由由几段时间构成:同步段(SS),物理延时段(TSEG1),误差补偿段(TSEG2),实时同步补偿段(SJW)。采样点是接收机采样确定电平高低的位置,在TSEG1段之后,大部分情况为百分之80%,车厂会提相应要求。采样点位置如下图:
  • CAN速率与采样点配置:如上代码所示CAN速率是由几个时间段参数计算而成,ST提供了工具帮助我们生成针对不同速率与采样点位置的参数,软件截图如下:
  • CAN总线负载率:总线负载率=总线每秒上传输的实际bit的总时间/1s *100%。原理非常简单,波特率的定义就是每秒CAN总线上可以传输多少CAN数据bit,总线负载率自然就是总线实际传输的bit数量比上总线可以承载的最大bit数了。CAN FD由于支持速率可变,总线占用时间的计算就稍微麻烦一些,需要分开计算:

十六宿舍 原创作品,转载必须标注原文链接。

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个

STM32+收发器实现CAN和485总线相关推荐

  1. CAN总线对比485总线

    CAN总线和RS485总线的定义 CAN是控制器局域网络(Controller Area Network, CAN)的简称,是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的,并最终成为国际标 ...

  2. “基于485总线的评分系统”

    "基于485总线的评分系统"说明 (一)设计思路和方法 RS485为半双工通信.只有通信双方一方处于发送,一方处于接收时,通信才能正常进行.本程序模拟modebus协议,采用主.从 ...

  3. CAN总线和485总线的区别

    1. RS485标准只规定了物理层而没有规定链路层,CAN是规定了物理层和链路层,换句话说,CAN用硬件实现了硬件标准化和协议标准化,当然485也有自己的通用协议MODBUS. 2. CAN硬件支持总 ...

  4. 基于485总线的评分系统

    基于485总线的评分系统 程序设计目标: 通过本案例加深理解RS485通信方式,实现上位机的主控制器与所有的下位机进行通信. 程序运行效果说明: 通过RS232/RS485转换器将多个带有485模块的 ...

  5. 基于485总线的评分系统双机实验报告

    本来还想着做多机的,但老师已经打分了就算了.为了压缩到6页删减了很多内容,将就看吧 基于485总线的评分系统实验报告 实验目标: 通过本案例加深理解RS485通信方式,实现上位机的主控制器与所有的下位 ...

  6. 485总线调试问题总结

    不同的芯片可以支持的节点数不同,MAX3085支持256个节点,MAX487支持128个节点. 一.项目内容 十通道MCU的工装利用UM3085E(英联)芯片,通过485总线与PC进行通信.设计两种通 ...

  7. MFC 485总线通信总结1

    最近有一个项目,需要读取9个表测量值,每个表都支持485通信,而一般PC并没有这么多串口,所以采用485总线形式,一主多从,读取各个表测量值. 我是一个初学者,在这里总结记录一下,若有不足之处,请大家 ...

  8. stm32多块开发板can总线互联卡死问题

    单块板子在接入can总线时没有任何问题,但是多块板子同时接入can时,基本只有一块是可以用的,其他板子会卡死,起初认定是总线连接的问题,试过总线上接入120ohm电阻一只或两只,都没有效果,通过kei ...

  9. 通讯可以并联吗_工业控制知识:吃透RS485通讯的连接方式,接485总线就简单多了...

    RS485被广泛使用,可以支持ModBus协议.由于其简单.价优.可靠和成熟,因此,被广泛应用于工业控制.智能仪器和电力通信. 我们来看看RS485的一个典型组网结构: 理论上,RS485总线的传输距 ...

最新文章

  1. 冯·诺伊曼奖得主Jorge Nocedal:增强学习中零阶优化方法及其应用(附演讲视频和PPT)
  2. 查看apk的签名信息和签名文件的信息
  3. luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)
  4. 一文带你了解腾讯位置服务的开发与接入
  5. JavaScript和Java的区别
  6. Java Exceptions
  7. VPP电源控制(VPP Power)-- 由DC-DC变换集成电路MC34063组成
  8. 大学四年Java学习路线规划,所有私藏资料我都贡献出来了,我要是早知道就好了
  9. 角度与弧度的转换 C语言
  10. 【机器学习】实验一 实验报告
  11. Android Q 正式命名为 Android 10
  12. 【7月cocos学习笔记】
  13. Docker 的数据持久化项目实战
  14. lammps教程:实例讲解npt、nvt系综的选择
  15. 常用简体中文字体转Unicode和Unicode 2编码对照表
  16. 将数据库导入SQL Server里
  17. Linux USB 3.0驱动分析—UAC驱动分析
  18. 水位报警仪电极式传感器感知水位分级式水位监测
  19. 清华大学计算机操作系统网易公开课笔记(持续更新)
  20. linux和win玩复古游戏,在Linux上玩复古游戏的5种最佳方式 | MOS86

热门文章

  1. 是未来的超级计算机还是只是一场炒作?
  2. 前进的路上,我们永不止步
  3. 利用C语言获取设备的MAC address
  4. 大航海时代 收夺全攻略
  5. 《Adobe After Effects CS4经典教程》——1.2 创建项目并导入素材
  6. 基于SpringBoot的医院门诊管理系统,高质量毕业论文范例-可直接参考使用,附源码和数据库脚本,项目导入运行视频教程,论文撰写教程
  7. 浏览器详谈及其内部工作机制 —— web开发必读
  8. HTTP认证之基本认证——Basic(*)
  9. 解决:利用IDEA的右上角图标打开jsp文件
  10. 自媒体原创视频怎么做?有哪些类型可以做?