• A48基于NRF24L01的无线心率血氧体温检测


    任务

    1. 使用51系列单片机
    2. 使用体温检测传感器M601(类似DS18B20,但精度更高,体积更小)
    3. 使用MAX30102模块(本次使用的是带串口的MAX30102模块,直接通过串口获取心率血氧数值)
    4. 使用NRF24L01完成无线传输

    实物

    (PCB略微随意了点,不过不影响功能实现,PS:可找我定制。)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    程序

    主机

    /*******************************************************************************

    * 文件名称:基于NRF24L01的无线心率血氧体温检测

    * 实验目的:1.

    * 2.

    * 程序说明:完整程序Q:2772272579;@: itworkstation@ hotmail.com

    * 日期版本:本项目分享关键细节,熟悉使用单片机的可做参考代码。完整讲解+源代码工程可联系获取,可定制。

    *******************************************************************************/

    #include "config.h"
    #include "lcd1602.h"
    #include "NRF24L01.h"
    #include "usart.h"
    //数据存储结构
    typedef struct 
    {
    	u8 heartRate;
    	u8 so2Date;
    	u8 wd_ds18b20; //温度整数
    }STRUCT_DATA;
    
    STRUCT_DATA recData[2];
    
    void DataInit(void)
    {
    	u8 i=0;
    	for(i=0;i<2;i++)
    	{
    		recData[i].heartRate = 88;
    		recData[i].so2Date = 98;
    		recData[i].wd_ds18b20 = 25;  //温度整数
    	}
    }
    
    u8 CheckVal(char c)
    {
    	u8 ret=0;
    	if((c>='0')&&(c<='9'))
    		ret=1;
    	return ret;	
    }
    
    void main()
    {
    	u8 count_rec=0;
    	Init_1602();
    	NRF24L01Int();
    	DataInit();
    	
    	Usart_Init();
    	
    	delay_ms(2000);
    	write_string(1,0,"R1 28 C  088  98");
    	write_zifu(1,5,0xdf);	//显示 °	
    	write_string(2,0,"R2 28 C  088  98");
    	write_zifu(2,5,0xdf);	//显示 °	
    	
    	NRFSetRXMode();//设置为接收模式
    	
    	while(1)
    	{
    		NRFSetRXMode();//设置为接收模式,每次接收数据前都要设置!!!
    	
    		while(count_rec<10 && IRQ==1)
    		{
    			GetDate(RevTempDate0,RevTempDate1);
    			delay_ms(100);
    			count_rec ++;
    		}
    		GetDate(RevTempDate0,RevTempDate1);
    		count_rec = 0;
    			
    		// 从机1数据
    		if((CheckVal(RevTempDate0[0])) && (CheckVal(RevTempDate0[1])) && (CheckVal(RevTempDate0[2])))
    		{
    			recData[0].heartRate = (RevTempDate0[0] - '0')*100 + (RevTempDate0[1] - '0')*10 + (RevTempDate0[2] - '0');
    		}
    		if((CheckVal(RevTempDate0[3])) && (CheckVal(RevTempDate0[4])))
    		{
    			recData[0].so2Date = (RevTempDate0[3] - '0')*10 + (RevTempDate0[4] - '0');
    		}
    		if((CheckVal(RevTempDate0[5])) && (CheckVal(RevTempDate0[6])) && (CheckVal(RevTempDate0[7])))
    		{
    			recData[0].wd_ds18b20 = (RevTempDate0[6] - '0')*10 + (RevTempDate0[7] - '0');
    		}
    		write_sfm(1,3,2,recData[0].wd_ds18b20);
    		
    		write_sfm(1,9,3,recData[0].heartRate);
    		
    		write_sfm(1,14,2,recData[0].so2Date);
    		
    		//  从机2数据
    		if((CheckVal(RevTempDate1[0])) && (CheckVal(RevTempDate1[1])) && (CheckVal(RevTempDate1[2])))
    		{
    			recData[1].heartRate = (RevTempDate1[0] - '0')*100 + (RevTempDate1[1] - '0')*10 + (RevTempDate1[2] - '0');
    		}
    		if((CheckVal(RevTempDate1[3])) && (CheckVal(RevTempDate1[4])))
    		{
    			recData[1].so2Date = (RevTempDate1[3] - '0')*10 + (RevTempDate1[4] - '0');
    		}
    		if((CheckVal(RevTempDate1[5])) && (CheckVal(RevTempDate1[6])) && (CheckVal(RevTempDate1[7])))
    		{
    			recData[1].wd_ds18b20 = (RevTempDate1[6] - '0')*10 + (RevTempDate1[7] - '0');
    		}
    		write_sfm(2,3,2,recData[1].wd_ds18b20);
    		
    		write_sfm(2,9,3,recData[1].heartRate);
    		
    		write_sfm(2,14,2,recData[1].so2Date);
    		
    		printf("R1:\r\n");
    		printf("%bu℃\r\n",recData[0].wd_ds18b20);
    		printf("%bu N/M\r\n",recData[0].heartRate);
    		printf("%bu%%\r\n\r\n",recData[0].so2Date);
    		
    		printf("R2:\r\n");
    		printf("%bu℃\r\n",recData[1].wd_ds18b20);
    		printf("%bu N/M\r\n",recData[1].heartRate);
    		printf("%bu%%\r\n\r\n",recData[1].so2Date);
    		
    		write_string(1,0,"R");
    		write_string(2,0,"R");
    		delay_ms(100);
    		
    		write_string(1,0," ");
    		write_string(2,0," ");
    		delay_ms(100);
    		
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    从机

    /***************************************** 
    功能:NRF24L01无线通讯,  从机1
    *****************************************/
    #include "config.h"
    #include "NRF24L01.h"
    #include "DS18B20.h"
    #include "usart.h"
    
    char TxDate[TX_DATA_WITDH];
    char RxDate[RX_DATA_WITDH];
    
    
    u8 heartRate = 88;
    u8 so2Date = 98;
    int wd_ds18b20 = 250;
    
    
    u8 CheckVal(char c)
    {
    	u8 ret=0;
    	if((c>='0')&&(c<='9'))
    		ret=1;
    	return ret;	
    }
    
    u16 Getval(char *str)
    {
    	u16 ret=0;
    	while(*str)
    	{
    		if((CheckVal(*str))==1)
    		{
    			ret=ret*10;
    			ret+=(*str-'0');
    			
    		}
    		str++;
    	}
    	return ret;
    }
    
    void main()
    {
    	u16 TimeReadMX30102=0,TimeReadDS18B20=0;
    	u8 m=0;
    	
    	Usart_Init();
    	NRF24L01Int();
    	
    	wd_ds18b20=Ds18b20ReadTemp();
    	wd_ds18b20=wd_ds18b20/256;
    	wd_ds18b20=wd_ds18b20+40;
    	
    	delay_ms(1000);
    	
    	TxDate[0]=heartRate/100%10+'0';
    	TxDate[1]=heartRate%100/10+'0';
    	TxDate[2]=heartRate%10+'0';
    	
    	TxDate[3]=so2Date%100/10+'0';
    	TxDate[4]=so2Date%10+'0';
    	
    	TxDate[5]=wd_ds18b20/100%10+'0';
    	TxDate[6]=wd_ds18b20%100/10+'0';
    	TxDate[7]=wd_ds18b20%10+'0';
    	
    	while(1)
    	{		
    		TimeReadMX30102++;
    		if(TimeReadMX30102==100L)
    		{
    			of1=0;
    			printf("AT+HEART\r\n");//查询心跳
    		}
    		else if(TimeReadMX30102>200)
    		{
    			of1=0;
    			printf("AT+SPO2\r\n");//查询血氧
    			TimeReadMX30102=0;
    		}
    		if(of1!=0)
    		{
    			m=of1;
    			delay_ms(10);
    			if(m==of1)
    			{
    				if(uart1buffer[0]=='+')
    				{
    					for(m=0;m<of1;m++)
    					{
    						if(uart1buffer[m]=='=')
    						{
    							break;
    						}
    					}
    					switch(uart1buffer[1])
    					{
    						case 'H':							
    							heartRate=Getval(uart1buffer+m+1);
    							break;
    						case 'S':							
    							so2Date=Getval(uart1buffer+m+1);
    							if(so2Date >= 100)
    								so2Date=99;
    							break;	
    						default:
    							break;
    
    					}				
    				}
    				of1=0;
    			}
    		}
    		TimeReadDS18B20++;
    		if(TimeReadDS18B20>400L)
    		{
    			TimeReadDS18B20=0;
    	
    			wd_ds18b20=Ds18b20ReadTemp();
    			wd_ds18b20=wd_ds18b20/256;
    			wd_ds18b20=wd_ds18b20+40;
    				
    			TxDate[0]=heartRate/100%10+'0';
    			TxDate[1]=heartRate%100/10+'0';
    			TxDate[2]=heartRate%10+'0';
    			
    			TxDate[3]=so2Date%100/10+'0';
    			TxDate[4]=so2Date%10+'0';
    			
    			TxDate[5]=wd_ds18b20/100%10+'0';
    			TxDate[6]=wd_ds18b20%100/10+'0';
    			TxDate[7]=wd_ds18b20%10+'0';
    			
    			NRFSetTxMode(TxDate);//发送测试
    			while(CheckACK());	//检测是否发送完
    		}
    		delay_ms(10);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    体温检测模块

    体温模块类似DS18B20驱动,但略有不同,在于读取出的数值需要进行转换:
    例如, 40 °C 对应寄存器值 0x 00 00 //寄存器值需要是int型有符号变量!!!,40°寄存器才是0;低于40°时寄存器值是负的。

    150 °C 对应寄存器值 0x 6E 00
    -70 °C 对应寄存器值 0x 92 00

    #ifndef __DS18B20_H__
    #define __DS18B20_H__
    
    #include "config.h"
    
    //--定义使用的IO口--//
    sbit DSPORT=P3^7;
    
    //--声明全局函数--//
    void Delay1ms(uint );
    uchar Ds18b20Init();
    void Ds18b20WriteByte(uchar com);
    uchar Ds18b20ReadByte();
    void  Ds18b20ChangTemp();
    void  Ds18b20ReadTempCom();
    int Ds18b20ReadTemp();
    
    
    
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    #include "DS18B20.h"
    /*******************************************************************************
    * 函 数 名         : Delay1ms
    * 函数功能		   : 延时函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    
    void Delay1ms(uint y)
    {
    	uint x;
    	for( ; y>0; y--)
    	{
    		for(x=110; x>0; x--);
    	}
    }
    /*******************************************************************************
    * 函 数 名         : Ds18b20Init
    * 函数功能		   : 初始化
    * 输    入         : 无
    * 输    出         : 初始化成功返回1,失败返回0
    *******************************************************************************/
    
    uchar Ds18b20Init()
    {
    	uchar i;
    	DSPORT = 0;			 //将总线拉低480us~960us
    	i = 70;	
    	while(i--);//延时642us
    	DSPORT = 1;			//然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
    	i = 0;
    	while(DSPORT)	//等待DS18B20拉低总线
    	{
    		Delay1ms(1);
    		i++;
    		if(i>5)//等待>5MS
    		{
    			return 0;//初始化失败
    		}
    	
    	}
    	return 1;//初始化成功
    }
    
    /*******************************************************************************
    * 函 数 名         : Ds18b20WriteByte
    * 函数功能		   : 向18B20写入一个字节
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    
    void Ds18b20WriteByte(uchar dat)
    {
    	uint i, j;
    
    	for(j=0; j<8; j++)
    	{
    		DSPORT = 0;	     	  //每写入一位数据之前先把总线拉低1us
    		i++;
    		DSPORT = dat & 0x01;  //然后写入一个数据,从最低位开始
    		i=6;
    		while(i--); //延时68us,持续时间最少60us
    		DSPORT = 1;	//然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
    		dat >>= 1;
    	}
    }
    /*******************************************************************************
    * 函 数 名         : Ds18b20ReadByte
    * 函数功能		   : 读取一个字节
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    
    
    uchar Ds18b20ReadByte()
    {
    	uchar byte, bi;
    	uint i, j;	
    	for(j=8; j>0; j--)
    	{
    		DSPORT = 0;//先将总线拉低1us
    		i++;
    		DSPORT = 1;//然后释放总线
    		i++;
    		i++;//延时6us等待数据稳定
    		bi = DSPORT;	 //读取数据,从最低位开始读取
    		/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
    		byte = (byte >> 1) | (bi << 7);						  
    		i = 4;		//读取完之后等待48us再接着读取下一个数
    		while(i--);
    	}				
    	return byte;
    }
    /*******************************************************************************
    * 函 数 名         : Ds18b20ChangTemp
    * 函数功能		   : 让18b20开始转换温度
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    
    void  Ds18b20ChangTemp()
    {
    	Ds18b20Init();
    	Delay1ms(1);
    	Ds18b20WriteByte(0xcc);		//跳过ROM操作命令		 
    	Ds18b20WriteByte(0x44);	    //温度转换命令
    	//Delay1ms(100);	//等待转换成功,而如果你是一直刷着的话,就不用这个延时了
       Delay1ms(10);
    }
    /*******************************************************************************
    * 函 数 名         : Ds18b20ReadTempCom
    * 函数功能		   : 发送读取温度命令
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    
    void  Ds18b20ReadTempCom()
    {	
    
    	Ds18b20Init();
    	Delay1ms(1);
    	Ds18b20WriteByte(0xcc);	 //跳过ROM操作命令
    	Ds18b20WriteByte(0xbe);	 //发送读取温度命令
    	 Delay1ms(10);
    }
    /*******************************************************************************
    * 函 数 名         : Ds18b20ReadTemp
    * 函数功能		   : 读取温度
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    extern void UsartSendchar(uchar dat );
    
    int Ds18b20ReadTemp()
    {
    	int temp = 0;
    	uchar tmh, tml;
    	Ds18b20ChangTemp();			 	//先写入转换命令
    	Ds18b20ReadTempCom();			//然后等待转换完后发送读取温度命令
    	tml = Ds18b20ReadByte();		//读取温度值共16位,先读低字节
    	tmh = Ds18b20ReadByte();		//再读高字节
    	//UsartSendchar(tml);
    	//UsartSendchar(tmh);
    	temp = tmh;
    	temp <<= 8;
    	temp |= tml;
    	return temp;
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151

    NRF24L01模块驱动

    /*****************************************
    创建:燃烧电子
    时间:2022.5.22
    功能:NRF24L01射频模块头文件
    *****************************************/
    #ifndef _NRF24L01_H_
    #define _NRF24L01_H_
    
    #include "config.h"
    sbit CE=P1^2;  //RX/TX模式选择端
    sbit SCLK=P1^7;	//SPI时钟端
    sbit MISO=P1^6;	//SPI主机输出从机输出端
    
    sbit IRQ=P1^4; //可屏蔽中断端
    sbit MOSI=P1^1;	//SPI主机输出从机输入端
    sbit CSN=P1^3; //SPI片选端//就是SS
    
    
    /*******************************************************/
    
    #define TX_ADDR_WITDH 5	//发送地址宽度设置为5个字节
    #define RX_ADDR_WITDH 5	//接收地址宽度设置为5个字节
    #define TX_DATA_WITDH 8//发送数据宽度/字节
    #define RX_DATA_WITDH 8//接收数据宽度/字节
    
    /*******************命令寄存器***************************/
    #define  R_REGISTER      0x00//读取配置寄存器
    #define  W_REGISTER      0x20//写配置寄存器
    #define  R_RX_PAYLOAD 	 0x61//读取RX有效数据
    #define  W_TX_PAYLOAD	 0xa0//写TX有效数据
    #define  FLUSH_TX		 0xe1//清除TXFIFO寄存器
    #define  FLUSH_RX		 0xe2//清除RXFIFO寄存器
    #define  REUSE_TX_PL     0xe3//重新使用上一包有效数据
    #define  NOP             0xff//空操作
    /******************寄存器地址****************************/
    #define  CONFIG          0x00//配置寄存器
    #define  EN_AA			 0x01//使能自动应答
    #define  EN_RXADDR       0x02//接收通道使能0-5个通道
    #define  SETUP_AW        0x03//设置数据通道地址宽度3-5
    #define  SETUP_RETR      0x04//建立自动重发
    #define  RF_CH           0x05//射频通道设置
    #define  RF_SETUP        0x06//射频寄存器
    #define  STATUS          0x07//状态寄存器
    #define  OBSERVE_TX      0x08//发送检测寄存器
    #define  CD              0x09//载波
    #define  RX_ADDR_P0      0x0a//数据通道0接收地址
    #define  RX_ADDR_P1      0x0b//数据通道1接收地址
    #define  RX_ADDR_P2      0x0c//数据通道2接收地址
    #define  RX_ADDR_P3      0x0d//数据通道3接收地址
    #define  RX_ADDR_P4      0x0e//数据通道4接收地址
    #define  RX_ADDR_P5      0x0f//数据通道5接收地址
    #define  TX_ADDR         0x10//发送地址
    #define  RX_PW_P0        0x11//P0通道数据宽度设置
    #define  RX_PW_P1        0x12//P1通道数据宽度设置
    #define  RX_PW_P2        0x13//P2通道数据宽度设置
    #define  RX_PW_P3        0x14//P3通道数据宽度设置
    #define  RX_PW_P4        0x15//P4通道数据宽度设置
    #define  RX_PW_P5        0x16//P5通道数据宽度设置
    #define  FIFO_STATUS     0x17//FIFO状态寄存器
    /*******************相关函数声明**************************/
    uchar NRFACK();
    uchar NRFSPI(uchar date);
    uchar NRFReadReg(uchar RegAddr);
    uchar NRFWriteReg(uchar RegAddr,uchar date);
    uchar NRFReadRxDate(uchar RegAddr,uchar *RxDate,uchar DateLen);
    uchar NRFWriteTxDate(uchar RegAddr,uchar *TxDate,uchar DateLen);
    
    void NRFSetTxMode(uchar *TxDate);
    void NRF24L01Int();
    void NRFSetRXMode();
    
    uchar CheckACK();
    extern void GetDate();
    uchar NRFRevDate(uchar *RevDate);
    
    extern uchar bdata sta;
    extern uchar RevTempDate0[RX_DATA_WITDH];//通道0接收数据
    extern uchar RevTempDate1[RX_DATA_WITDH];//通道1接收数据
    /*********************************************************/
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    /***************************************** 
    功能:NRF24L01射频模块C文件(从机发射部分)
    *****************************************/
    #include "NRF24L01.h"
    
    uchar RevTempDate0[RX_DATA_WITDH];//通道0接收数据
    uchar RevTempDate1[RX_DATA_WITDH];//通道1接收数据
    
    uchar code RxAddr0[]={0x34,0x43,0x10,0x10,0x01};//编号1接收地址这个地址和发送方地址一样!
    uchar code TxAddr[]={0x34,0x43,0x10,0x10,0x01};//发送地址	 ,编号1
    
    //uchar code RxAddr1[]={0xc2,0xc2,0xc2,0xc2,0xc1};//编号2
    //uchar code TxAddr[]={0xc2,0xc2,0xc2,0xc2,0xc1};//发送地址	 ,编号2
    
    /*****************状态标志*****************************************/
    uchar  bdata sta;   //状态标志
    sbit RX_DR=sta^6;
    sbit TX_DS=sta^5;
    sbit MAX_RT=sta^4;
    /**********************延时函数**************************/
    void NRFDelay(uint t)
    {
       uint x,y;
       for(x=t;x>0;x--)
        for(y=110;y>0;y--);
    }
    /*****************SPI时序函数******************************************/
    uchar NRFSPI(uchar date)
    {
        uchar i;
       	for(i=0;i<8;i++)          // 循环8次
       	{
    	  if(date&0x80)
    	    MOSI=1;
    	  else
    	    MOSI=0;   // byte最高位输出到MOSI
       	  date<<=1;             // 低一位移位到最高位
       	  SCLK=1; 
    	  if(MISO)               // 拉高SCK,nRF24L01从MOSI读入1位数据,同时从MISO输出1位数据
       	    date|=0x01;       	// 读MISO到byte最低位
       	  SCLK=0;            	// SCK置低
       	}
        return(date);           	// 返回读出的一字节
    }
    /**********************NRF24L01初始化函数*******************************/
    void NRF24L01Int()
    {
    	NRFDelay(2);//让系统什么都不干
    	CE=0;
    	CSN=1;  
    	SCLK=0;
    	IRQ=1; 
    }
    /*****************SPI读寄存器一字节函数*********************************/
    uchar NRFReadReg(uchar RegAddr)
    {
       uchar BackDate;
       CSN=0;//启动时序
       NRFSPI(RegAddr);//写寄存器地址
       BackDate=NRFSPI(0x00);//写入读寄存器指令  
       CSN=1;
       return(BackDate); //返回状态
    }
    /*****************SPI写寄存器一字节函数*********************************/
    uchar NRFWriteReg(uchar RegAddr,uchar date)
    {
       uchar BackDate;
       CSN=0;//启动时序
       BackDate=NRFSPI(RegAddr);//写入地址
       NRFSPI(date);//写入值
       CSN=1;  
       return(BackDate);
    }
    /*****************SPI读取RXFIFO寄存器的值********************************/
    uchar NRFReadRxDate(uchar RegAddr,uchar *RxDate,uchar DateLen)
    {  //寄存器地址//读取数据存放变量//读取数据长度//用于接收
        uchar BackDate,i;
    	CSN=0;//启动时序
    	BackDate=NRFSPI(RegAddr);//写入要读取的寄存器地址
    	for(i=0;i<DateLen;i++) //读取数据
    	  {
    	     RxDate[i]=NRFSPI(0);
    	  } 
        CSN=1;
       return(BackDate); 
    }
    /*****************SPI写入TXFIFO寄存器的值**********************************/
    uchar NRFWriteTxDate(uchar RegAddr,uchar *TxDate,uchar DateLen)
    { //寄存器地址//写入数据存放变量//读取数据长度//用于发送
       uchar BackDate,i;
       CSN=0;
       BackDate=NRFSPI(RegAddr);//写入要写入寄存器的地址
       for(i=0;i<DateLen;i++)//写入数据
         {
    	    NRFSPI(*TxDate++);
    	 }   
       CSN=1;
       return(BackDate);
    }
    /*****************NRF设置为发送模式并发送数据******************************/
    void NRFSetTxMode(uchar *TxDate)
    {  //发送模式 
    	NRFSPI(FLUSH_RX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
    	NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
        CE=0;   
       	NRFWriteTxDate(W_REGISTER+TX_ADDR,RxAddr0,TX_ADDR_WITDH);//写寄存器指令+P0地址使能指令+发送地址+地址宽度
    	NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH);//为了应答接收设备,接收通道0地址和发送地址相同
    	NRFWriteTxDate(W_TX_PAYLOAD,TxDate,TX_DATA_WITDH);//写入数据 
    	/******下面有关寄存器配置**************/
      	NRFWriteReg(W_REGISTER+EN_AA,0x01);       // 使能接收通道0自动应答
      	NRFWriteReg(W_REGISTER+EN_RXADDR,0x01);   // 使能接收通道0
      	NRFWriteReg(W_REGISTER+SETUP_RETR,0x0a);  // 自动重发延时等待250us+86us,自动重发10次
      	NRFWriteReg(W_REGISTER+RF_CH,0x40);         // 选择射频通道0x40
      	NRFWriteReg(W_REGISTER+RF_SETUP,0x07);    // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益
      	NRFWriteReg(W_REGISTER+CONFIG,0x0e);      // CRC使能,16位CRC校验,上电	
    	CE=1;	
    	NRFDelay(5);//保持10us秒以上
    } 
    /*****************NRF设置为接收模式并接收数据******************************/
    //接收模式
    void NRFSetRXMode()
    {
    	NRFSPI(FLUSH_RX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
    	NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
        CE=0;
      	NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,RxAddr0,TX_ADDR_WITDH);  // 接收设备接收通道0使用和发送设备相同的发送地址
      	NRFWriteReg(W_REGISTER+EN_AA,0x01);               // 使能接收通道0自动应答
      	NRFWriteReg(W_REGISTER+EN_RXADDR,0x01);           // 使能接收通道0
    
    	NRFWriteReg(W_REGISTER+RX_PW_P0,TX_DATA_WITDH);  // 接收通道0选择和发送通道相同有效数据宽度
    
    
      	NRFWriteReg(W_REGISTER+RF_CH,0x40);                 // 选择射频通道0x40
      	
      	NRFWriteReg(W_REGISTER+RF_SETUP,0x07);            // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益*/
      	NRFWriteReg(W_REGISTER+CONFIG,0x0f);              // CRC使能,16位CRC校验,上电,接收模式
      	CE = 1; 
    	NRFDelay(5);    
    }
    /****************************检测是否有接收到数据******************************/
    uchar CheckACK()
    {  //用于发射模式接收应答信号
    	sta=NRFReadReg(R_REGISTER+STATUS);                    // 返回状态寄存器
    	if(TX_DS||MAX_RT) //发送完毕中断
    	{
    	   NRFWriteReg(W_REGISTER+STATUS,0xff);  // 清除TX_DS或MAX_RT中断标志
    	   CSN=0;
    	   NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!  
           CSN=1; 
    	   return(0);
    	}
    	else
    	   return(1);
    }
    /*************************接收数据*********************************************/
    //void GetDate()				 
    //{
    //    uchar RX_P_NO;//接收通道号
    //	sta=NRFReadReg(R_REGISTER+STATUS);//发送数据后读取状态寄存器
    //    if(RX_DR)				// 判断是否接收到数据
    //     {
    //	   RX_P_NO=sta&0x0e;//获取通道号
    //	   CE=0;//待机
    //	   switch(RX_P_NO)
    //	    {
    //		   case 0x00:NRFReadRxDate(R_RX_PAYLOAD,RevTempDate0,RX_DATA_WITDH);break;// 从RXFIFO读取数据通道0
    //		   case 0x02:NRFReadRxDate(R_RX_PAYLOAD,RevTempDate1,RX_DATA_WITDH);break;// 从RXFIFO读取数据通道1
    //		   default:break;
    //		}
    //	   write_string(1,4,RevTempDate0);//LCD602液晶显示
    //	   write_string(2,5,RevTempDate1); 
    //	   NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标
    //	   CSN=0;
    //	   NRFSPI(FLUSH_RX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!! 
    //	   CSN=1;		 
    //     }
    //    //NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标	  
    //} 
    /******************判断是否接收收到数据,接到就从RX取出*********************/
    //用于接收模式
    uchar NRFRevDate(uchar *RevDate)
    {
       	 uchar RevFlags=0;
    	 sta=NRFReadReg(R_REGISTER+STATUS);//发送数据后读取状态寄存器
         if(RX_DR)				// 判断是否接收到数据
    	 {
    	    CE=0; 			//SPI使能
    		NRFReadRxDate(R_RX_PAYLOAD,RevDate,RX_DATA_WITDH);// 从RXFIFO读取数据
    		RevFlags=1;	   //读取数据完成标志
    	  }
    	  NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标
    	   CSN=0;
    	   NRFSPI(FLUSH_RX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!! 
    	   CSN=1;
    	 return(RevFlags);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
  • 相关阅读:
    proto3-2语法
    vue3-vueRouter v4.x
    java毕业设计智慧问诊系统Mybatis+系统+数据库+调试部署
    docker搭建MySQL主从复制
    加快网络安全事件响应的六个步骤
    Loading class `com.mysql.jdbc.Driver‘. This is deprecated.
    【Netty】一、高性能NIO通信框架Netty-快速入门
    深入浅出SSH
    《三体》中的两大假说-射手与农场主
    数字图像处理——实验四 数字图像的边缘检测实验
  • 原文地址:https://blog.csdn.net/qq_20467929/article/details/126117359