精华内容
下载资源
问答
  • 一、设计内容 设计通过串行口实现两台PC机之间串行通信的硬件和软件。...2.双机串行通信,在一台PC机键入字符,从8251A的发送端发送给另一台PC机,另一台PC机的 8251A的接收端接收,然后在屏幕上显示出来。
  • 异步串行通信&Proteus}例一 ●题目 ●原理图 ●Method  ●Method 1  ●Method 2 例一  ●题目  ●原理图  ●Method   ●Method 1 这道例题是来自丁向荣老师的《单片微机原理与接口技术》上的演示...

    单片机STC15双机通信&异步串行通信&Proteus

    例一

     ●题目

    在这里插入图片描述

     ●原理图

    在这里插入图片描述
    在这里插入图片描述

     ●Method

      ●Method 1

    这道例题是来自丁向荣老师的《单片微机原理与接口技术》上的演示例题。
    在这里插入图片描述
    同时,也给出了代码,同时在老师的网课中也进行了演示,代码如下:

    #include<STC15.H>
    #include<intrins.h>
    
    #define uchar unsigned char
    #define uint unsigned int
    	
    uchar temp;    
    uchar temp1; 
    
    void Delay100ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	_nop_();
    	i = 5;
    	j = 52;
    	k = 195;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	SCON = 0x50;		//8位数据,可变波特率
    	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
    	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
    	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
    	TL1 = 0xE0;		//设定定时初值
    	TH1 = 0xFE;		//设定定时初值
    	ET1 = 0;		//禁止定时器1中断
    	TR1 = 1;		//启动定时器1
    }
    //-----------------------------------IO口初始化函数-----------------------------//
    void GPIO(void)
    {
    	P0M1=0;
    	P0M0=0;
    	P1M1=0;
    	P1M0=0;
    	P2M1=0;
    	P2M0=0;
    	P3M1=0;
    	P3M0=0;
    	P4M1=0;
    	P4M0=0;
    	P5M1=0;
    	P5M0=0;
    
    }
    void main()
    {
    	GPIO();    //调用IO初始化函数
    	UartInit();//调用串行口1初始化函数
    	ES=1;
    	EA=1;
    	while(1)
    	{
    		temp=P3;
    		temp=temp&0X0C;  //读P33,P32引脚的输入状态值
    		SBUF=temp;       //串行发送
    		while(TI==0);    //检测穿行发送是否结束
    		TI=0;
    		Delay100ms();	   //设置串行发送间隔
    	}
    }
    
    void uart_isr() interrupt 4  //串行接收中断函数
    {
    	if(RI==1)
    	{
    		RI=0;
    		temp1=SBUF;
    		switch(temp1&0x0c)
    	   	{
    			case 0x00:P4=0XFE;break;
    			case 0x04:P4=0XFD;break;
    			case 0x08:P4=0XFB;break;
    			default:P4=0XF7;break;
    		  }		
    	}
    }
    

      但实际的运行结果是:双机串行异步通信只能发送一次数据,即刚上电时刻自锁开关的状态值,之后无论开关状态如何,数据都不能继续发送。(没有尝试过其他的热启动复位)。网上有说是发送中断标志位TI或(和)接收中断标志位RI实际上没有清零的,也没有解决。
    在这里插入图片描述

      ●Method 2

    参照官方例程和DL的代码,修改出了一个暂且在仿真中能正常使用的的程序(区别以及原因ing):

    #include<STC15.H>
    #include<intrins.h>
    
    #define uchar unsigned char
    #define uint unsigned int
    	
    uchar temp;     //串行发送临时传递参数
    uchar temp1;    //串行接收临时传递参数 
    uchar busy;     //正忙标志(数据正在传输)
    void Delay100ms();		//@11.0592MHz
    void GPIO(void);      //IO口初始化函数
    void UartInit(void);	//9600bps@11.0592MHz 串行口1初始化函数
    void SendData(void);  //发送串口数据 (串行发送采用查询方式)
    	
    void main()
    {
    	GPIO();
    	UartInit();
    	ES=1;   //允许串行口1中断
    	EA=1;   //总中断允许控制位
    	while(1)
    	{
          SendData();  //发送串口数据
    	}
    }
    
    //-----------------------------------IO口初始化函数-----------------------------//
    void GPIO(void)
    {
    	P0M1=0;
    	P0M0=0;
    	P1M1=0;
    	P1M0=0;
    	P2M1=0;
    	P2M0=0;
    	P3M1=0;
    	P3M0=0;
    	P4M1=0;
    	P4M0=0;
    	P5M1=0;
    	P5M0=0;
    
    }
    
    //-------------------------------------串行口1初始化函数-----------------------------//
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	SCON = 0x50;		 //8位数据,可变波特率
    	AUXR |= 0x40;		 //定时器1时钟为Fosc,即1T
    	AUXR &= 0xFE;		 //串口1选择定时器1为波特率发生器
    	TMOD &= 0x0F;		 //设定定时器1为16位自动重装方式
    	TL1 = 0xE0;		   //设定定时初值
    	TH1 = 0xFE;		   //设定定时初值
    	ET1 = 0;		     //禁止定时器1中断
    	TR1 = 1;		     //启动定时器1
    }
    //------------------------串行接收中断函数 (串行接收采用中断方式)---------------------//
    void uart_isr() interrupt 4
    {
    	if(RI)
    	{
    	  RI=0;       //清除RI位
          temp1=SBUF;
          switch(temp1&0x0c)
    	   	{
    			   case 0x00:P4=0XFE;break;
    			   case 0x04:P4=0XFD;break;
    			   case 0x08:P4=0XFB;break;
    			   default:P4=0XF7;break;
    		  }		
       }
    	 if(TI)
        {
           TI = 0;         //清除TI位
           busy = 0;       //清零正忙标志
        }
    
    }
    
    
    //-----------------------发送串口数据(串行发送采用查询方式)-------------------------------//
    void SendData(void)
    {
        while(busy);          //等待前面的数据发送完成
        temp = P3;            //
    	temp=temp&0X0C;       //读取P33,P32引脚的输入状态值 
        busy = 1;             //将正忙标志置1,
    	SBUF = temp;          //串行发送
    }
    
    展开全文
  • F1双机spi通信.zip

    2021-01-07 14:37:29
    通信简单,数据传输速率块,SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入...
  • 实验七 双机通信

    千次阅读 2019-01-18 11:03:17
    在两个单片机上实现串行通信,将一块单片机上的按键信息发送到另一块单片机上用八个数码管动态显示出键值。 二、实验目的 1.学习双机通信的基本使用方法。 2.学习双机通信程序的编程方法。 三、实验原理 89C51...

    实验七  双机通信

    一、实验要求

    在两个单片机上实现串行通信,将一块单片机上的按键信息发送到另一块单片机上用八个数码管动态显示出键值。

    、实验目的

    1.学习双机通信的基本使用方法。

    2.学习双机通信程序的编程方法

    、实验原理

    89C51单片机片内有一个可编程的全双工的异步通信串行口。所谓全双工就是两个单片机之间串行数据可同时双向传输。异步传输,就是收、发双方使用各自的时钟控制发送和接受过程。89C51的串行口有四种工作方式,波特率可通过软件设置片内的定时器/计数器来控制。每当串行口接收或发送一个字节完毕,均可发出中断请求。而在串行通信中,收、发双方发送或接收的波特率必须一致。

    、实验内容

    本次实验的实验内容为串口双机通信,可以完成的功能:在一方的矩形键盘按下一个值,在另一方的数码管上动态显示。矩阵键盘采用4×4式,其中前十个键为0-9数字,后六个键为A-F字母。A-F代表着不同的波特率,通过按下不同的键,可以设置不同的波特率。A-137.5b/s,B-1.2kb/s,C-2.4kb/s,D-4.8kb/s,E-9.6kb/s,F-19.2kb/s.获取键值的方式为:扫描法。

    、实验程序框图

    ‪C:\Users\WYP\Desktop\1.JPG

    ‪C:\Users\WYP\Desktop\2.JPG

    、实验电路图

    、实验程序

    发送方:

     

    ORG 0000H

    LJMP MAIN

    ORG 1000H

    MAIN:MOV SP,#60H

    MOV TMOD,#20H      

    MOV TH1,#1DH      

    MOV TL1,#1DH

    SETB TR1

    MOV SCON,#40H    

    LOP1:MOV P2,#0F0H  

    MOV A,P2           

    ANL A,#0F0H       

    MOV B,A           

    XRL A,#0F0H     

    JZ LOP1           

    LCALL Delay       

    MOV A,P2          

    ANL A,#0F0H     

    CJNE A,B,LOP1     

    LCALL SCAN           

    LCALL LOOSE     

    LCALL GET_KEY    

    AJMP LOP1            

    SCAN:MOV R3,#0    

    MOV R2,#0FEH       

    SCAN2:MOV A,R2

    MOV P2,A         

    MOV A,P2         

    JB ACC.4,LOOP1   

    MOV R4,#0       

    RET

    LOOP1:JB ACC.5,LOOP2

    MOV R4,#04H      

    RET

    LOOP2:JB ACC.6,LOOP3

    MOV R4,#08H     

    RET

    LOOP3:JB ACC.7,SCAN1

    MOV R4,#0CH      

    RET

    SCAN1:INC R3    

    MOV A,R2

    RL A

    MOV R2,A

    JB ACC.4,SCAN2   

    RET

    LOOSE:MOV P2,#0F0H  

    MOV A,P2

    ANL A,#0F0H

    XRL A,#0F0H

    JNZ LOOSE

    RET

    GET_KEY: MOV A,R4

    ADD A,R3        

    MOV B,A         

    MOV DPTR,#TAB   

    MOVC A,@A+DPTR

    MOV SBUF,A          

    JNB TI,$        

    CLR TI           

    MOV A,B         

    CJNE A,#0AH,GET0   

    MOV TL1,#1DH

    MOV TH1,#1DH

    AJMP GET5

    GET0:CJNE A,#0BH,GET1   

    MOV TL1,#0E8H

    MOV TH1,#0E8H

    AJMP GET5

    GET1:CJNE A,#0CH,GET2  

    MOV TL1,#0F4H

    MOV TH1,#0F4H

    AJMP GET5

    GET2:CJNE A,#0DH,GET3

    MOV TL1,#0FAH

    MOV TH1,#0FAH

    AJMP GET5

    GET3:CJNE A,#0EH,GET4  

    MOV TL1,#0FDH

    MOV TH1,#0FDH

    AJMP GET5

    GET4:CJNE A,#0FH,GET5  

    MOV PCON,#80H

    MOV TL1,#0FDH

    MOV TH1,#0FDH

    GET5:RET

    Delay:MOV R2,#20

    DEY1:MOV R3,#248

    NOP

    DJNZ R3,$

    DJNZ R2,DEY1

    RET

    SJMP $

    TAB:DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71H,00H

    END

     

    接受方:

     

    ORG 0000H

    LJMP MAIN

    ORG 0023H

    LJMP REXE       

    ORG 1000H

    MAIN:MOV SP,#60H

    MOV TMOD,#20H    

    MOV TH1,#1DH      

    MOV TL1,#1DH

    MOV SCON,#50H    

    SETB TR1

    SETB ES

    SETB EA

    MOV R6,#7      

    MOV 30H,#77H     

    MOV R1,#31H        

    DISP:MOV P1,#00H   

    MOV P2,30H         

    LCALL Delay       

    MOV P1,#01H     

    MOV P2,31H

    LCALL Delay

    MOV P1,#02H     

    MOV P2,32H

    LCALL Delay

    MOV P1,#03H     

    MOV P2,33H

    LCALL Delay

    MOV P1,#04H     

    MOV P2,34H

    LCALL Delay

    MOV P1,#05H     

    MOV P2,35H

    LCALL Delay

    MOV P1,#06H     

    MOV P2,36H

    LCALL Delay

    MOV P1,#07H      

    MOV P2,37H

    LCALL Delay

    AJMP DISP        

    REXE:CLR RI         

    MOV A,SBUF        

    LCALL Option   

    MOV @R1,A      

    INC R1         

    DJNZ R6,REC    

    MOV R1,#31H        

    MOV R6,#7

    REC:RETI

    Delay: MOV R2,#10

    DEY1:MOV R3,#248

    NOP

    DJNZ R3,$

    DJNZ R2,DEY1

    RET

    Option:CJNE A,#77H,Opt0

    MOV TL1,#1DH        

    MOV TH1,#1DH

    ACALL Rest             

    AJMP Opt5

    Opt0:CJNE A,#7CH,Opt1

    MOV TL1,#0E8H       

    MOV TH1,#0E8H

    ACALL Rest          

    AJMP Opt5

    Opt1:CJNE A,#39H,Opt2

    MOV TL1,#0F4H

    MOV TH1,#0F4H

    ACALL Rest

    AJMP Opt5

    Opt2:CJNE A,#5EH,Opt3

    MOV TL1,#0FAH

    MOV TH1,#0FAH

    ACALL Rest

    AJMP Opt5

    Opt3:CJNE A,#79H,Opt4

    MOV TL1,#0FDH

    MOV TH1,#0FDH

    ACALL Rest

    AJMP Opt5

    Opt4:CJNE A,#71H,Opt5

    MOV PCON,#80H

    MOV TL1,#0FDH

    MOV TH1,#0FDH

    ACALL Rest

    Opt5:RET

    Rest:MOV 30H,A   

    MOV 31H,#0        

    MOV 32H,#0

    MOV 33H,#0

    MOV 34H,#0        

    MOV 35H,#0

    MOV 36H,#0

    MOV 37H,#0

    MOV R1,#30H        

    MOV R6,#1      

    RET

    END

     

    八、实验总结

    通过在两个单片机上实现串行通信,将一块单片机上的按键信息发送到另一块单片机上用八个数码管动态显示出键值。我们学习了双机通信的基本使用方法并且学习了双机通信程序的编程方法。

     

    展开全文
  • UART 双机 通信

    2010-09-17 12:22:44
    掌握简单的串行双机通信方法。 【硬件接法】 详见电路原理图。 【实验步骤】 ISP下载开关扳到“00”,用Flash Magic软件下载程序文件夹“MCU#1”下的“UART-Two.hex”,暂时不要运行。 ISP下载开关扳到“10”...
  • 掌握89C51单片机异步串行口的通信原理和编程 掌握串行口工作方式1的使用及其波特率的计算 二、实验内容 打开ISIS 7 Professional,参照图9.1设计仿真电路原理图 编写程序实现: (1)串行口设为工作方式1,其中一...

    单片机双机通信

    一、实验目的

    二、实验内容

    三、实验步骤

    四、C代码如下

    五、实验结果

    六、实验体会


    一、实验目的

    1. 掌握89C51单片机异步串行口的通信原理和编程
    2. 掌握串行口工作方式1的使用及其波特率的计算

    二、实验内容

    1. 打开ISIS 7 Professional,参照图9.1设计仿真电路原理图
    2. 编写程序实现:

    (1)串行口设为工作方式1,其中一个单片机为发送方,另外一个单片机为接收方。发送数据块大小为10字节,存放在发送方单片机内部RAM的50H~59H中,通过发送方单片机的串行口发出,再通过接收方单片机串行口接收。接收数据块存放到接收方单片机内部RAM的60H~69H中。实验中数据传输通过程序查询控制,查询数据有否已发送或已收到。发送数据之前,发送方单片机持续发送联络信号AAH给接收方单片机,收到接收方单片机的应答信号后才开始发送数据块。发送和接收的数据均传送到各自P2的7SEG-BCD数码管显示器上显示。

    (2)串行口设为工作方式1,其中一个单片机为发送方,另外一个单片机为接收方,发送数据块大小为10字节,存放在发送方单片机内部RAM的50H~59H中,通过发送方单片机的串行口发出,再通过接收方单片机串行口接收。接收数据块存放到接收方单片机内部RAM的60H~69H中。实验中数据传输通过程序中断控制。发送数据之前,发送方单片机持续发送联络信号AAH给接收方单片机,收到接收方单片机的应答信号后才开始发送数据块。发送和接收的数据均传送到各自P2口的7SEG-BCD数码管显示器上显示。

    三、实验步骤

    本实验电路如图9.1所示,所用元器件清单见表9.1

                                                                                              图9.1   单片机双机通信实验电路

    表9.1 单片机双机通信实验电路元器件清单
    元器件编号 元器件名称 说明
    U1、U3 AT89C52 AT89C52单片机
    U2、U4 74HC245 8位总线驱动器
      7SEG-BCD 7段BCD数码管显示器

    四、C代码如下

    /*在P2口显示启动信号AA、回答信号BB、发送数据*/
    #include <REG52.H>  /*special function register declarations*/
    #include <stdio.h>  /*prototype declarations for I/O functions*/
    #include <intrins.h>
    #include <Absacc.h>
    #include <string.h>
    #include <ctype.h>
    #define byte unsigned char
    #define uchar unsigned char
    #define word unsigned int
    #define uint unsigned int
    #define ulong unsigned long
    #define BYTE unsigned char
    #define WORD unsigned int
    #define TRUE 1
    #define FALSE 0
    sbit SEND_RECI_CTRL=P1^0;
                   /*SEN_RECI_LINE=1,设置发送;SEND_RECI_LINE=0,设置接收*/
    void initUart(void);  /*初始化串行口波特率,使用定时器2*/
    void send(uchar idata *d);  /*发送函数*/
    void receive(uchar idata *d);  /*接收函数*/
    void initUart(void);  /*初始化串行口*/
    void time(unsigned int ucMs);  //延时单位:ms
    uchar idata sbuf [10] _at_ 0x50;/*发送内容*/
    uchar idata rbuf [10] _at_ 0x60;/*接收缓冲区*/
    /******** main函数 ***********/
    void main (void) {
    	initUart(); /*初始化串行口*/
    	time(10); /*延时等待外围器件完成复位*/
    	if(SEND_RECI_CTRL){ /*如果发送标志有效,则初始化发送数组数据*/
    		uchar i;
    		for(i=0;i<10;i++){
    			sbuf[i]=0x20+i;
    		}
    	}
    	if(SEND_RECI_CTRL){ /*发送*/
    		send(sbuf);
    	}
    	else{ /*接收*/
    		receive(rbuf);
    	}
    	while(TRUE){}
    	}
    /************ 初始化串行口波特率 **************/
    void initUart(void) /*初始化串行口波特率,使用定时器1*/
    {
    /*SEtup the serial port for 9600 baud at 11.0592MHz*/
    SCON=0x50;  //串行口工作在工作方式1下
    TMOD=0x20;
    PCON=0x0;
    TH1=0xfd;
    TCON=0x40;
    }
    void send(uchar idata *d) /*发送函数*/
    {
    	uchar i;
    	do{
    		P2=0xaa;
    		SBUF=0xaa; /*发送联络信号*/
    		while(TI==0){}TI=0;
    			while(RI==0){}RI=0;
    			}while((SBUF^0xbb)!=0);  /*乙机未准备好,继续联络*/
    	P2=SBUF;time(500);
    			
    			/*发送一组数据,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,*/
    			for(i=0;i<10;i++){
    				P2=d[i];time(500);
    				SBUF=d[i];  /*发送一个数据*/
    				while(TI==0){}TI=0;
    				}
    			}
    
          void receive(uchar idata *d)  /*接收数据*/
    			{
    				uchar i;
    				do{
    					while(RI==0){}RI=0;
    						P2=SBUF;time(500);
    					}while((SBUF^0xaa)!=0);  /*判甲机请求否*/
    				P2=0xbb;time(500);
    					SBUF=0xbb;  /*发应答信号*/
    					while(1){\
    						for(i=0;i<10;i++){
    							while(RI==0){}RI=0;
    								d[i]=SBUF;  /*接收一个数据*/
    								P2=d[i];  /*显示接收数据*/
    							}
    						}
    					}
    
    /********************************************
    *  函数说明:延时5us,晶振改变时只需要改变这一个函数!
        1.对于11.0592MHz晶振而言,需要2个_nop_();
        2.对于22.1184MHz晶振而言,需要4个_nop_();
    *  入口参数:无
    * 返回:无
    * 创建日期:20010623
    * 作者:张齐
    ********************************************/
    void delay_5us(void)  //延时5us,晶振改变时只改变这一个函数
    {
    	_nop_();
    	_nop_();
    	//_nop_();
    	//_nop_();
    }
    /**************** delay_50us ******************/
    void delay_50us(void)  //延时50us
    {
    	unsigned char i;
    	for(i=0;i<4;i++)
    	{
    		delay_5us();
    	}
    }
    /***************** 延时100us *******************/
    void delay_100us(void)  //延时100us
    {
    	delay_50us();
    	delay_50us();
    }
     
    /************ 延时单位:ms **************/
    void time(unsigned int ucMs)  //延时单位:ms
    {
    	unsigned char j;
    	while(ucMs>0){
    		for(j=0;j<10;j++) delay_100us();
    		ucMs--;
    	}
    }

    五、实验结果

    六、实验体会

    在修改程序的时候,需要我们认真了解程序才可以进行修改,只有我们了解每一句代码的含义,我们才能正确的把程序改成自己需要的功能。

    展开全文
  • CAN:控制器局域网络 (Controller Area Network, CAN) ,是一种串行通信总线。 部分用户使用起来,并不是想象中那么的顺利。 CAN 通信,可以分为主、从机。 基于rt-thread,已经有CAN的驱动框架,可以快速实现CAN...

    RT-Thread 应用笔记 - 不正确使用LOG也会引发hard fault

    RT-Thread 应用笔记 - RTC Alarm组件的使用

    RT-Thread 应用笔记 - freemodbus RTU RS485 从机

    RT-Thread 应用笔记 - freemodbus RTU RS485 主机

    RT-Thread 应用笔记 - libmodbus RTU RS485 从机

    RT-Thread 应用笔记 - libmodbus RTU RS485 主机

    RT-Thread 应用笔记 - STM32 CAN 通信双机

    RT-Thread USB学习笔记系列

     

    背景

    • CAN:控制器局域网络 (Controller Area Network, CAN) ,是一种串行通信总线。
    • 部分用户使用起来,并不是想象中那么的顺利。
    • CAN 通信,可以分为主、从机。
    • 基于rt-thread,已经有CAN的驱动框架,可以快速实现CAN数据的收发。
    • 这里基于STM32F103 实现CAN数据收发的功能。
    • 部分使用CAN的用户,发现无法通信,需要注意CAN本身引脚的配置与波特率、ID、滤波器等的设置。

     

    前言

    • 嵌入式软件工程师,需要了解原理图,了解引脚定义,如CAN 通信使用的CAN_TXD、 CAN_RXD 引脚等等。
    • 我的板子,MCU 为STM32F103C8T6, Flash与SRAM都相对不大。
    • UART1用于rt-thread MSH串口。
    • PA11、PA12接CAN收发器
    • STM32F103 内部有CAN 控制器

     

    移植

    • 首先搭建STM32F103最小系统,调通MSH 串口,有个LED指示会更好。
    • 根据原理图,CAN 引脚配置: xxx_msp.c文件:增加

    2020-12-08_215655.png

    /**
    * @brief CAN MSP Initialization
    * This function configures the hardware resources used in this example
    * @param hcan: CAN handle pointer
    * @retval None
    */
    void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
    {
        GPIO_InitTypeDef GPIO_InitStruct = {0};
        if(hcan->Instance==CAN1)
        {
            /* Peripheral clock enable */
            __HAL_RCC_CAN1_CLK_ENABLE();
    
            __HAL_RCC_GPIOA_CLK_ENABLE();
            /**CAN GPIO Configuration
            PA11     ------> CAN_RX
            PA12     ------> CAN_TX
            */
            GPIO_InitStruct.Pin = GPIO_PIN_11;
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
            GPIO_InitStruct.Pin = GPIO_PIN_12;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
        }
    }
    
    /**
    * @brief CAN MSP De-Initialization
    * This function freeze the hardware resources used in this example
    * @param hcan: CAN handle pointer
    * @retval None
    */
    void HAL_CAN_MspDeInit(CAN_HandleTypeDef* hcan)
    {
        if(hcan->Instance==CAN1)
        {
            /* Peripheral clock disable */
            __HAL_RCC_CAN1_CLK_DISABLE();
    
            /**CAN GPIO Configuration
            PA11     ------> CAN_RX
            PA12     ------> CAN_TX
            */
            HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
        }
    }
    • 通过rt-thread ENV工具,menuconfig,开启CAN,BSP中,配置CAN1(STM32F103C8,只有CAN1)

    2020-12-08_214903.png

    2020-12-08_215036.png

    2020-12-08_215125.png

    • rt-thread ENV工具: scons --target=mdk5,生成Keil MDK5工程。
    • 编译通过,下载发现,没任何CAN通信的功能。

     

    CAN通信Demo

    • 配置好CAN设备驱动后,需要用户开发CAN通信应用。
    • 这里使用RT-Thread 官方提供的CAN 通信例子:
    /*
     * 程序清单:这是一个 CAN 设备使用例程
     * 例程导出了 can_sample 命令到控制终端
     * 命令调用格式:can_sample can1
     * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
     * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
    */
    
    #include <rtthread.h>
    #include "rtdevice.h"
    
    #define CAN_DEV_NAME       "can1"      /* CAN 设备名称 */
    
    static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
    static rt_device_t can_dev;            /* CAN 设备句柄 */
    
    /* 接收数据回调函数 */
    static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
    {
        /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
        rt_sem_release(&rx_sem);
    
        return RT_EOK;
    }
    
    static void can_rx_thread(void *parameter)
    {
        int i;
        rt_err_t res;
        struct rt_can_msg rxmsg = {0};
    
        /* 设置接收回调函数 */
        rt_device_set_rx_indicate(can_dev, can_rx_call);
    
    
    #if 0
        struct rt_can_filter_item items[5] =
        {
            RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */
            RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */
            RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 1, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */
            RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr 为 - 1 */
            {0x555, 0, 0, 1, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */
        };
        struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */
        /* 设置硬件过滤表 */
        res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
        RT_ASSERT(res == RT_EOK);
    #endif
    
        while (1)
        {
            /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
            rxmsg.hdr = -1;
            /* 阻塞等待接收信号量 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
            /* 从 CAN 读取一帧数据 */
            rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
            /* 打印数据 ID 及内容 */
            rt_kprintf("ID:%x", rxmsg.id);
            for (i = 0; i < 8; i++)
            {
                rt_kprintf("%2x", rxmsg.data[i]);
            }
    
            rt_kprintf("\n");
        }
    }
    
    int can_sample(int argc, char *argv[])
    {
        struct rt_can_msg msg = {0};
        rt_err_t res;
        rt_size_t  size;
        rt_thread_t thread;
        char can_name[RT_NAME_MAX];
    
        if (argc == 2)
        {
            rt_strncpy(can_name, argv[1], RT_NAME_MAX);
        }
        else
        {
            rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
        }
        /* 查找 CAN 设备 */
        can_dev = rt_device_find(can_name);
        if (!can_dev)
        {
            rt_kprintf("find %s failed!\n", can_name);
            return RT_ERROR;
        }
    
        /* 初始化 CAN 接收信号量 */
        rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    
        /* 以中断接收及发送方式打开 CAN 设备 */
        res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
        RT_ASSERT(res == RT_EOK);
        /* 创建数据接收线程 */
        thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
        if (thread != RT_NULL)
        {
            rt_thread_startup(thread);
        }
        else
        {
            rt_kprintf("create can_rx thread failed!\n");
        }
    
        msg.id = 0x78;              /* ID 为 0x78 */
        msg.ide = RT_CAN_STDID;     /* 标准格式 */
        msg.rtr = RT_CAN_DTR;       /* 数据帧 */
        msg.len = 8;                /* 数据长度为 8 */
        /* 待发送的 8 字节数据 */
        msg.data[0] = 0x00;
        msg.data[1] = 0x11;
        msg.data[2] = 0x22;
        msg.data[3] = 0x33;
        msg.data[4] = 0x44;
        msg.data[5] = 0x55;
        msg.data[6] = 0x66;
        msg.data[7] = 0x77;
        /* 发送一帧 CAN 数据 */
        size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
        if (size == 0)
        {
            rt_kprintf("can dev write data failed!\n");
        }
    
        return res;
    }
    
    void can_send_test(void)
    {
        struct rt_can_msg msg = {0};
        rt_size_t  size;
        static rt_uint8_t num = 0;
        
        msg.id = 0x78;              /* ID 为 0x78 */
        msg.ide = RT_CAN_STDID;     /* 标准格式 */
        msg.rtr = RT_CAN_DTR;       /* 数据帧 */
        msg.len = 8;                /* 数据长度为 8 */
    
        /* 待发送的 8 字节数据 */
        msg.data[0] = 0x00;
        msg.data[1] = num++;
        msg.data[2] = 0x22;
        msg.data[3] = 0x33;
        msg.data[4] = num++;
        msg.data[5] = 0x55;
        msg.data[6] = 0x66;
        msg.data[7] = 0x77;
        /* 发送一帧 CAN 数据 */
        size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
        if (size == 0)
        {
            rt_kprintf("can dev write data failed!\n");
        }
    }
    
    /* 导出到 msh 命令列表中 */
    MSH_CMD_EXPORT(can_sample, can device sample);
    MSH_CMD_EXPORT(can_send_test, can send test);
    • 代码编译完成,下载。串口运行:can_sample,发现CAN通信失败!!
    • 接好USB转CAN,打开电脑的USB CAN工具

    2020-12-08_215917.png

    • 打开USB转CAN(当然,若有其他的CAN主机或设备,可以不使用USB转CAN),注意波特率,这里配置为1Mbps。
    • 重启,再次运行can_sample,发现,接收到STM32发出的CAN数据帧。
    • 多次运行 can_send_test,电脑端可以接受数据。
    • 注意,我关闭了滤波器功能(这个功能,抽时间讲下),也就是CAN总线上所以的ID来的数据,都可以接收!!

    2020-12-08_220258.png

    2020-12-08_220334.png

    • CAN的双向收发测试完成!!

     

    总结

    • CAN 是一种通信总线,需要通过ID来标识每个设备或主机。
    • CAN 波特率最大为1Mbps,注意波特率的计算公式,设置方式。
    • 滤波器,可以用来屏蔽一些ID,如只接收某些ID,这样可以防止CAN频繁的中断与解析!
    • CAN接线方式:CANH ---- CANH, CANL ---- CANL。可以选择共地,差分信号,不共地,依旧可以正常通信。
    • CAN总线与RS485一样,长距离通信,最好有终端匹配电阻,如120欧姆。终端电阻接在CAN总线的两端。

    2020-12-08_221411.png

    • CAN 总线的特性,可以实现总线上,多个主机。
    展开全文
  • zigbee cc2530 SPI通讯(双机主从通讯)

    千次阅读 2018-08-08 15:48:21
    SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入)、SDO(数据输出)、...
  • 单片机原理及应用 实验 : 串口通信的应用 实验目的 1.掌握MCS-51单片机的串行口应用的程序设计和调试方法。 2.学习双机通信的常识。 3.掌握双机通信程序状态字的设置方法。 4.学习双机通信程序的编制方法。
  • 单片机实验报告-串口实验

    万次阅读 2018-07-22 16:20:44
    一.实验目的 1. 掌握 51 单片机串口工作原理。 2. 掌握 51 单片机串口初始化编程。...(1)编程实现:编程实现:甲、乙双机串行通信,双机的 RXD 和 TXD 相互交叉相连,甲机的 P0 口接 8 个开关,乙机的 P...
  • “微机接口虚拟实验台”是提供进行...5、8251串行通信 实验8:单机自发自收实验 实验9:双机异步通信实验 6、综合实验 实验10:交通灯控制 实验11:霓虹灯控制 实验12:环境温度监控 实验13:步进电机控制
  • 设计基于 RS-485 总线和 51 单片机的主从式双机通信系统,通信采用 10 位异步串行通信帧标准格式,即 1 位起始位、8 位数据位、1 个停止位,无奇偶校验和硬件 数据流控制,通信波特率为 9600 bps; ② 由主机通过 ...
  • 一、 51单片机串行口工作原理MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信。1.串行端口的基本特点8031单片机的串行端口有4种基本工作方式,通过...
  • 6.2.1 异步串行通信 6.2.2 同步串行通信 6.3 实现代码分析 6.3.1 程序主体设计及关键模块分析 6.3.2 使用API通信 6.4 实践拓展 第7章 串口调试精灵 7.1 串口调试工具实现的基本要求 7.2 串口调试精灵的编程实现 ...
  • 通信网络技术

    2014-08-06 13:30:59
    应用光学原理,由光发送机产生光束,将电信号变为光信号,再把光信号导入光纤,在另一端由光接收机接收光纤上传来的光信号,并把它变为电信号,经解码后再处理。与其它传输介质比较,光纤的电磁绝缘性能好、信号衰小...
  • 第一节串行通信概述 第二节MCS-51单片机串行口结构及控制寄存器 一、MCS-51串行口的结构 二、串行口控制寄存器SCON 三、专用寄存器PCON 第三节MCS-51串行口的工作方式 一、方式0 二、方式1 三、方式2和方式3 四、...
  • 例8.5 甲乙串行通讯 例8.6 甲乙通信 LED 例9.1 外部数据存储器清零 例9.8 RAM缓冲区 例9.9 RAM74LS164 例10.1 DS18B20 例10.2 AT24C02读写 例11.1 DAC0832 例11.2 波形发生器 例11.3 信号发生器 例11.4 AD转换与LED ...
  • 接口与计算机网络

    2011-12-26 11:11:12
    编写程序,实现双机串行通信,能正确进行文件或字符的发送和接收。 二. 相关技术 三. 方案设计 四. 实现与测试 五.分析与总结 参考书目:(五号,宋体加粗) [1] 余永权,汤荣江.《计算机接口与通信》,华南理工...
  • BASIC语言及其串行通信组件(MSCOMM32.OCX)编程实现了两个计算机之间的数据交换, 并通过这个例子说明:组件技术把数据和代码进行封装,通过事件来响应外部变化; RS232接口标准化程度高,对双机通信及互联网访问提供了...
  • 红外 数据 收发

    2010-09-17 12:20:56
    学习简单的串行双机通信方法。 【硬件接法】 详见电路原理图。 【实验步骤】 ISP下载开关扳到“01”,用Flash Magic软件下载程序文件“IRDA-TX.hex”,暂时不要运行。 ISP下载开关扳到“11”,用Flash Magic...
  • 一个8XX51单片机的双机通信系统波特率为9600bps,fosc=12MHz,用中断方式编写程序,将甲机片内RAM 30H~3FH的数据块通过串行口传送到乙机的片内RAM 40~4FH单元中。 二、调试原理 使用keil软件完成本实验程序在keil...
  • 8.2 可编程串行通信接口芯片16550与8250 8.3 可编程并行通信接口芯片8255 8.4 可编程定时/计数器芯片8253与8254 8.5 A/D与D/A转换接口 8.6 打印机接口 8.7 显示适配器接口 8.8 软硬盘接口 8.9 调制解调器 8.10 简单...
  • 8.2 可编程串行通信接口芯片16550与8250 8.3 可编程并行通信接口芯片8255 8.4 可编程定时/计数器芯片8253与8254 8.5 A/D与D/A转换接口 8.6 打印机接口 8.7 显示适配器接口 8.8 软硬盘接口 8.9 调制解调器 8.10 简单...
  • 8.2 可编程串行通信接口芯片16550与8250 8.3 可编程并行通信接口芯片8255 8.4 可编程定时/计数器芯片8253与8254 8.5 A/D与D/A转换接口 8.6 打印机接口 8.7 显示适配器接口 8.8 软硬盘接口 8.9 调制解调器 8.10 简单...
  • 8.2 可编程串行通信接口芯片16550与8250 8.3 可编程并行通信接口芯片8255 8.4 可编程定时/计数器芯片8253与8254 8.5 A/D与D/A转换接口 8.6 打印机接口 8.7 显示适配器接口 8.8 软硬盘接口 8.9 调制解调器 8.10 简单...
  • 第6章 串行通信原理及操作流程 6.1 并行与串行基本通信方式 6.2 RS-232电平与TTL电平的转换 6.3 波特率与定时器初值的关系 6.4 51单片机串行口结构描述 6.5 串行口方式1编程与实现 6.6 串行口打印在调试程序中的...
  • 4.3 在VC++中用ActiveX控件实现与单片机的串行通信(293) 4.4 利用Windows API函数构造C++类实现串行通信(298) 4.5 用Win32 API实现PC机与多单片机的串行通信(304) 4.6 GPS接收机与PC机串行通信技术的开发与应用(311)...
  • 第5章阐述串行通信接口SCI,并给出第一个带中断的实例。1~5章介绍了学习一个新MCU完整要素(知识点)的入门。6~12章分别介绍GPIO的应用(键盘、LED及LCD)、定时器(含PWM)、串行外设接口SPI、Flash存储器在线...
  • 3.5 用VB通信控件开发微机与单片机的串行通信程序  3.6 RS—485收发器及组网中的有关问题  3.7 新型数字通信接口  3.8 Caller ID来电号码显示器原理与设计  3.9 新型FSK/DTMF兼容...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
热门标签
关键字:

双机串行通信原理