STM32+OOK通讯(OOK发送+OOK接收)+cubemx配置

一、简介

关于OOK通信,我的理解就是将要发送的信息转换成高低电平(即0和1),然后接收方通过对01进行解码获得信息。于是我用了非常朴素的字符串转二进制+AM调制来完成通信链。话不多说我们直接开始!!!

二、发送机详解

2.1 发送机cubemx配置

之前从来没有配置过的同学可以看一看我之前写的AHT20的配置。

发送机只需要配置一个东西,就是将你选定的高低电平输出引脚配置成OUTPUT!!

这里我选择了PC1作为输出引脚,你也可以选择自己心动的引脚嘉宾,但是一定要配成OUTPUT哦。

2.2 发送机代码呈现

很朴素的代码,字符串转换成二进制然后输出。

1.字符串转换成二进制

注意:此处每个字符转换成7个二进制编码,不是8个。

void charToBinary(char c, char* result) {  
    for (int i = 6; i >= 0; i--) {  
        result[6 - i] = (c >> i) & 1 ? '1' : '0';  
    }  
    result[7] = '\0'; 
}  
void stringToBinary(char* s, char* binary) {  
    int binaryIndex = 0;  
    const int binaryBufferSize = 1024; 
    char tempBinary[9];
  
    while (*s) {  
        charToBinary(*s++, tempBinary);  
        strcat(binary + binaryIndex, tempBinary);  
        binaryIndex += 7; 
    }  
}  
void numchar_to_output(char *s){
	int length=strlen(s);
	for (int i=0;i<length;i++){
		if(s[i]=='0'){
			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_RESET);
			HAL_Delay(0);
			HAL_UART_Transmit(&hlpuart1,(uint8_t*)c,strlen(c),500);
		}
		else if(s[i]=='1'){
			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_SET);
			HAL_Delay(0);
			HAL_UART_Transmit(&hlpuart1,(uint8_t*)b,strlen(b),500);
		}
	}
}

三个小函数,那么在主函数中如何调用呢?

2.主函数调用

先来几个定义:

char s[5000]="0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
//这是我设置的起始位。
char inputStr[500] = {0}; 
//要进行传输的字符串,比如说hello!!
char binary[1024] = {0};
//字符串转换成的二进制字符串

s[5000]这是我设置的起始位。因为我发现接收机接收到的波在没有输出的时候是高电平,所以我加了很多0来表示开始读取。
注意:0的个数要足够大。因为我输出的逻辑是一毫秒输出一个电平,在我写的字符串转二进制中,一个字符串转换成7个01编码。而0000000对应的正好是字符串结束符'\0',所以为了保险起见+担心采样的时间偏差,我加了一大串0作为起始符。
这样的好处还有一个:我设置的是将要发送的信息循环发送,也就是这个信息前面是一串0,后面也是一串0,在进行解码的时候只需要处理前面的0,后面的0会被解码为结束符'\0',字符串会自动结束,也就是说对信息后面的0不用进行处理。
主函数调用:

stringToBinary(inputStr, binary);
strcat(s,binary);
while(1){numchar_to_output(s);}

这样你就可以愉快地输出对应的高低电平了!

2.3 发送机端结构

单片机输出———————>

                                                 乘法器   —————> 功率放大器 ————> 天线

高频载波(20Mhz)———>

至此,发送端完成!!

三、接收端详解

3.1 接收端结构

天线 ——> 功率放大器 ——>滤波器 ——> 检波器 ——> 放大器 ——> 单片机处理

实际操作中我只用了天线、检波器和单片机。可能因为距离比较短,深刻原因是功率放大器没接负载or输入信号太大被烧了TT

单片机处理的整体思路是:先进行长度为100的小采样,再进行长度为5000的大采样。

前面已经提到过起始符是一大串0,发送频率是1k。我的采样频率设置为10k,也就是说一个字符对应采样为70个采样点。先进行长度为100的小采样,如果这100个点中有非0的值(也就是不在起始符中),就重新进行小采样。一直到小采样中所有点都是0值,也就是现在采集的这一段都在起始符中,则退出小采样进行大采样。大采样就包含了传递的字符串。

然后再对大采样进行解码,即可获得传递的信息。

3.2 接收机cubemx配置

需要配置一个定时器和一个ADC。

定时器我选用了TIM3

7200-1这个地方是根据设定的时钟以及你所期待的采样频率设置的。我希望采样频率是10khz,而我的时钟是72Mhz,72M除以7200正好是10k,后面记得-1哦。

ADC使用了ADC1,配置如下:

我采用了单端输入,由定时器3触发进行DMA采样。

刚开始DMA里面什么都没有,点一下加号进行设置。

配置结束。

3.3 接收机代码呈现

main.c

#define f0 10000
//采样频率
#define ADC_SNUM 100
//小采样大小
#define ADC_LNUM 5000
//大采样大小
__IO uint8_t ADC_con_flag = 0;

uint16_t adc_sample_data[ADC_SNUM];
//小采样的采样数组
uint16_t adc_sample_data2[ADC_LNUM];
//大采样的采样数组

char mes[20]={0};

int caiyang(void);
//判断小采样是不是都是0,如果都是0就进行大采样

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_LPUART1_UART_Init();
  MX_TIM3_Init();
  HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); 

  int flag=0;//小采样结束的标志
  flag=caiyang();
  HAL_Delay(0);
  while(!flag){
	flag=caiyang();
	HAL_Delay(0);
  }
  HAL_Delay(0);

  //开始进行大采样
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_sample_data2, ADC_LNUM);
	HAL_TIM_Base_Start(&htim3);
	while(!ADC_con_flag)
	{
		;
	}
	sprintf(mes,"flag is :%d\n",flag);
	HAL_UART_Transmit(&hlpuart1,(uint8_t*)mes,strlen(mes),500);
	for(int i=0;i<ADC_LNUM;i++){
		if(adc_sample_data2[i]>2200) adc_sample_data2[i]=1000;
            //此处我设置的是采样数值大于2200就判断为1,具体需要根据自己的情况设置。
		else adc_sample_data2[i]=0;
        //这里的处理是为了让数据变得更工整,便于后续的解码
		sprintf(mes,"%d\n",adc_sample_data2[i]);
		HAL_UART_Transmit(&hlpuart1,(uint8_t*)mes,strlen(mes),500);
	}
	output(adc_sample_data2);
    //这个函数是我自己写的解码函数,在output.c文件中。下文会提到
}



int caiyang(void){
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_sample_data, ADC_SNUM);
	HAL_TIM_Base_Start(&htim3);
	while(!ADC_con_flag)
	{
		;
	}
	for(int i=0;i<ADC_SNUM;i++){
		if(adc_sample_data[i]>2200) return 0;//有一就是return0
        //同样要根据自己的情况设置。
	}
	return 1;//都是0,开始读取!!!
}

output.c

#include <string.h>
#include <stdio.h>
#include "output.h"
#define ADC_LNUM 5000
char binaryStringToCharSimple(const char* binaryStr) {  
   
    unsigned char result = 0;  
    for (int i = 0; i < 7; i++) {  
        result = (result << 1) | (binaryStr[i] - '0');  
    }  
  
    return result;  
}  

void output(uint16_t* adc_sample_data2){
	char initial[ADC_LNUM/10];
	int t_num=0;
	int begin_num=0;
	while(adc_sample_data2[begin_num]==0)begin_num++;
	for(int i=begin_num-1;i<ADC_LNUM;i=i+10){
		int f_1=0;
		for(int j=i;j<i+10;j++){
			if(adc_sample_data2[j]>700)f_1++;
		}
		if(f_1>7)initial[t_num++]='1';
		else initial[t_num++]='0';
	}
	initial[t_num]='\0';
	char binaryStr[20];  
    char result[200]; 
  	int char_len=strlen(initial);
  	int begin=0,i=0,j=0;
  	 for (i = 0; i < char_len-7; i=i+7)
    {
    	for(j=i;j<i+7;j++){
    		binaryStr[j-i]=initial[j];
		}
		binaryStr[j-i]='\0';
       	char a=binaryStringToCharSimple(binaryStr);
      	result[begin]=a;
       	begin++;
    }
    for(i=char_len-7;i<char_len;i++)binaryStr[i-(char_len-7)]=initial[i];
    char a=binaryStringToCharSimple(binaryStr);
    result[begin]=a;
    begin++;
   	result[begin]='\0';
		HAL_UART_Transmit(&hlpuart1,(uint8_t*)result,strlen(result),500);
}

 output.h

#ifndef __OUTPUT_H__
#define __OUTPUT_H__


#endif

#include "main.h"
#include "usart.h"

void output(uint16_t adc_sample_data2[]);


ADC采样需要在你的stm32g4xx_it.c(不同的单片机不同,但都是xx_it)加上两句话:

extern uint8_t ADC_con_flag;
//这句在头文件下面加

//在DMA1_Channel1_IRQHandler函数中加一句
ADC_con_flag=1;

最后DMA1_Channel1_IRQHandler(void)应该是:

void DMA1_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_adc1);
  ADC_con_flag=1;
}

至此,代码部分结束!你只需要在串口输出上看解码的结果就可以了。

注意:代码中时不时跳出来的delay(0)是我发现如果不加上会卡死,这个也请根据实际情况调整。经过我的测试发现加上是必要的。

四、资料分享

由于发射机部分比较简单,所以就不分享工程了。

OK接收机部分工程如下:

链接:https://pan.baidu.com/s/1L3NiK3ZRC1kMg3RnPYlywg?pwd=6666 
提取码:6666 
--来自百度网盘超级会员V2的分享

百度网盘自取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值