关于通信方式的一些自我学习(uart、i2c、spi的一些最底层的逻辑以及运用方式)STM32F407上的一些实际日常应用

1.uart

(1)一些最基本的原理以及通信方式

首先其工作原理是将数据以串行方式进行发的,接收的时候将数据转换为并行数据。利用异步通信所以不需要时钟线适用于不同芯片、芯片对模块之间的控制。因此需要设置好波特率(115200、9500)数据位、停止位、奇偶效验位。

(2)实际应用中的一些具体操作

在实际应用中不管你是要发数据还是要收数据,首先得拿出一个空余的存储空间出来(buff)对uart进行初始化,首先对其映射的引脚进行初始化,设置波特率,中断的优先级,收或者发、数据位、停止位、奇偶效验位。最后利用定时器或者其他方式一直往buff里面写入数据,并且判断buff是否被填满,填满即可发送给所需要接受的设备即可。

收数据也需初始化上述的一系列操作,就依据发数据时所设定的波特率、数据位、停止位、奇偶效验位,等进行解包读取真实数据。

在我们一般的使用过程之中通常将其封装为8位,第一位和最后一位作为数据包的判断位,第一位如果正确将这个数据包进行解读,解读到最后一位如果也正确就对这个数据获取进行下一步的运用。如果第一位和最后一位有错误则对数据进行丢弃。

(3)具体代码如下

uart.c

#include "sys.h"
#include "usart.h"	
#include "led.h"
#include "delay.h"
// 	 
//Èç¹ûʹÓÃucos,Ôò°üÀ¨ÏÂÃæµÄÍ·Îļþ¼´¿É.
RingBuff_t Uart2_RingBuff,Uart1_RingBuff,Uart3_RingBuff;//´´½¨Ò>>¸öringBuffµÄ>>º³åÇø
uint16_t distance = 0;
//¼ÓÈëÒÔÏ´úÂë,Ö§³Öprintfº¯Êý,¶ø²>>ÐèҪѡÔñuse MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//±ê×¼¿âÐèÒªµÄÖ§³Öº¯Êý                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//¶¨Òå_sys_exit()ÒÔ±ÜÃâʹÓðëÖ÷>>úģʽ    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//Öض¨Òåfputcº¯Êý 
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//Ñ­>>··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
	USART1->DR = (u8) ch;      
	return ch;
}
#endif
 
//³õʼ>>¯IO ´®¿Ú1 
//bound:²¨ÌØÂÊ
void uart_init(u32 bound){
   //GPIO¶Ë¿ÚÉèÖÃ
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //ʹÄÜGPIOAʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//ʹÄÜUSART1ʱÖÓ
 
	//´®¿Ú1¶ÔÓ¦Òý½Å¸´ÓÃÓ³Éä
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9¸´ÓÃΪUSART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10¸´ÓÃΪUSART1
	
	//USART1¶Ë¿ÚÅäÖÃ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9ÓëGPIOA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//ËÙ¶È50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //ÍÆÍ츴ÓÃÊä³ö
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //ÉÏÀ­
	GPIO_Init(GPIOA,&GPIO_InitStructure); //³õʼ>>¯PA9£¬PA10

   //USART1 ³õʼ>>¯ÉèÖÃ
	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(USART1, &USART_InitStructure); //³õʼ>>¯´®¿Ú1
	
	USART_Cmd(USART1, ENABLE);  //ʹÄÜ´®¿Ú1 
	
	USART_ClearFlag(USART1, USART_FLAG_TC);

#if EN_USART1_RX	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//¿ªÆôÏà¹ØÖжÏ

	//Usart1 NVIC ÅäÖÃ
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//´®¿Ú1ÖжÏͨµÀ
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//ÇÀÕ¼ÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;		//×ÓÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
	NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ>>¯NVIC¼Ä´æÆ÷

#endif
}

void USART1_IRQHandler(void)                	//´®¿Ú1ÖжϷþÎñ³ÌÐò
{
	uint8_t rdata;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
	{		
		rdata = USART_ReceiveData(USART1);
		if(Write_RingBuff(&Uart1_RingBuff, rdata) == RINGBUFF_ERR){//>>º³åÇøÂúµÆÁÁ
			LED1=0;
		}else{
			LED1=1;
		}
	} 
} 

void uart2_v831_init(uint32_t bound){
   //GPIO¶Ë¿ÚÉèÖÃ
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
 
	//´®¿Ú2¶ÔÓ¦Òý½Å¸´ÓÃÓ³Éä
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource6,GPIO_AF_USART2); 
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_USART2); 
	
	//USART1¶Ë¿ÚÅäÖÃ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_5; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//ËÙ¶È50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //ÍÆÍ츴ÓÃÊä³ö
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //ÉÏÀ­
	GPIO_Init(GPIOD,&GPIO_InitStructure);

   //USART2 ³õʼ>>¯ÉèÖÃ
	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(USART2, &USART_InitStructure); //³õʼ>>¯´®¿Ú
	
	USART_Cmd(USART2, ENABLE);  //ʹÄÜ´®¿Ú2 
	
	USART_ClearFlag(USART2, USART_FLAG_TC);

	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//¿ªÆôÏà¹ØÖжÏ

	//Usart2 NVIC ÅäÖÃ
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//´®¿Ú2ÖжÏͨµÀ
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//ÇÀÕ¼ÓÅÏȼ¶
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//×ÓÓÅÏȼ¶
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
	NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ>>¯NVIC¼Ä´æÆ÷
}
 
void USART2_IRQHandler(void)                	//´®¿Ú2ÖжϷþÎñ³ÌÐò
{
	uint8_t rdata;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
	{	
		rdata = USART_ReceiveData(USART2);
		if(Write_RingBuff(&Uart2_RingBuff, rdata) == RINGBUFF_ERR){//>>º³åÇøÂúµÆÁÁ
			LED1=0;
		}else{
			LED1=1;
		}
	} 
} 

void uart3_init(uint32_t bound){
   //GPIO¶Ë¿ÚÉèÖÃ
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
 
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); 
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); 
	
	//USART1¶Ë¿ÚÅäÖÃ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//ËÙ¶È50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //ÍÆÍ츴ÓÃÊä³ö
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //ÉÏÀ­
	GPIO_Init(GPIOB,&GPIO_InitStructure);

   //USART3 ³õʼ>>¯ÉèÖÃ
	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(USART3, &USART_InitStructure); //³õʼ>>¯´®¿Ú
	
	USART_Cmd(USART3, ENABLE);  //ʹÄÜ´®¿Ú2 
	
	USART_ClearFlag(USART3, USART_FLAG_TC);

	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//¿ªÆôÏà¹ØÖжÏ

	//USART3 NVIC ÅäÖÃ
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;//´®¿Ú2ÖжÏͨµÀ
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//ÇÀÕ¼ÓÅÏȼ¶
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//×ÓÓÅÏȼ¶
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
	NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ>>¯NVIC¼Ä´æÆ÷
}

void USART3_IRQHandler(void)
{
	uint8_t rdata;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{	
		rdata = USART_ReceiveData(USART3);
		if(Write_RingBuff(&Uart3_RingBuff, rdata) == RINGBUFF_ERR){//>>º³åÇøÂúµÆÁÁ
			LED1=0;
		}else{
			LED1=1;
		}
	} 
} 

uint16_t get_distance(void)
{
	uint16_t mm = 0;
	uint8_t cmd = 0x55;
	static uint16_t i;
	i++;
	if(Uart3_RingBuff.Lenght == 2){
		i=0;
		uint8_t data = 0;
		Read_RingBuff(&Uart3_RingBuff, &data);
		mm = data;
		Read_RingBuff(&Uart3_RingBuff, &data);
		mm =  mm << 8 | data;
		//delay_us(1000);
		usart_send(USART3,&cmd,1);
	} 
	if(i==100 || Uart3_RingBuff.Lenght > 2){ //Ò>>Ãë
		RingBuff_Init(&Uart3_RingBuff);
		usart_send(USART3,&cmd,1);
	}
	return mm;
}

uint8_t DataDecode(RingBuff_t *ringbuff, uint8_t *data1, uint8_t *data2)      
{
	static uint8_t uart_dec_count;
	static uint8_t uart_rec_data[5];
	uint8_t ret = 1;
	if(Read_RingBuff(ringbuff, &uart_rec_data[uart_dec_count]) == RINGBUFF_ERR){
		return 1;
	}
	if((uart_dec_count == 0)&&(uart_rec_data[uart_dec_count] != 0x55)) {    		//¼ì²âµÚÒ>>¸öÊý¾ÝÊÇ·ñΪ0x55
		uart_rec_data[uart_dec_count] = 0;						
	} else if((uart_dec_count == 1)&&(uart_rec_data[uart_dec_count] != 0xaa)){      //¼ì²âµÚ¶þ¸öÊý¾ÝÊÇ·ñΪ0xaa
		uart_rec_data[uart_dec_count] = 0;
		uart_rec_data[uart_dec_count-1] = 0;
		uart_dec_count = 0;
	} else if((uart_dec_count == 4)&&(uart_rec_data[uart_dec_count] != 0xfa)){
		uart_rec_data[uart_dec_count] = 0;
		uart_rec_data[uart_dec_count-1] = 0;
		uart_rec_data[uart_dec_count-2] = 0;
		uart_rec_data[uart_dec_count-3] = 0;
		uart_rec_data[uart_dec_count-4] = 0;
		uart_dec_count = 0;
	} else {
		if(uart_dec_count == 4)//³É¹¦½ÓÊÕÒ>>Ö¡Êý¾Ý
		{
			*data1 = uart_rec_data[2];
			*data2 = uart_rec_data[3];
			ret = 0;
		}
		uart_dec_count ++;
		if(uart_dec_count == 5)
		{
			uart_dec_count = 0;
		}
	}
	return ret;	
} 
/* ½ÓÊÕjson×Ö·û´® */
int8_t receiveJson(RingBuff_t *ringbuff, char *str)
{
	static uint8_t reading,j;
	uint8_t readbuff,ok = 0;
	if(Read_RingBuff(&Uart1_RingBuff,&readbuff) == RINGBUFF_OK){
		if(readbuff == '{'){
			reading = 1;
			str[j++] = readbuff;
			ok = 0;
		}else if(readbuff == '}' && reading == 1){
			reading = 0;
			str[j++] = readbuff;  
			str[j++] = '\0';
			ok = 1;
		}else if(reading == 1){
			str[j++] = readbuff;
		}else {
			j = 0;
			reading = 0;
			ok = 0;
		}
	}
	return ok;
}

void usart_send(USART_TypeDef* USARTx, uint8_t*data, uint8_t len)
{
	uint8_t i;
	for(i=0;i<len;i++)
	{
		while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET); 
		USART_SendData(USARTx,data[i]);
	}
}

/**
* @brief  RingBuff_Init
* @param  RingBuff_t *ringbuff
* @return void
* @note   ³õʼ>>¯>>·ÐÎ>>º³åÇø
*/
void RingBuff_Init(RingBuff_t *ringbuff)
{
  //³õʼ>>¯Ïà¹ØÐÅÏ¢
  ringbuff->Head = 0;
  ringbuff->Tail = 0;
  ringbuff->Lenght = 0;
}

/**
* @brief  Write_RingBuff
* @param  uint8_t data
* @return FLASE:>>·ÐÎ>>º³åÇøÒÑÂú£¬Ð´Èëʧ°Ü;TRUE:дÈë³É¹¦
* @note   Íù>>·ÐÎ>>º³åÇøдÈëuint8_tÀàÐ͵ÄÊý¾Ý
*/
uint8_t Write_RingBuff(RingBuff_t *ringbuff, uint8_t data)
{
  if(ringbuff->Lenght >= RINGBUFF_LEN) //ÅжÏ>>º³åÇøÊÇ·ñÒÑÂú
  {
    return RINGBUFF_ERR;
  }
  ringbuff->Ring_data[ringbuff->Tail]=data;
  ringbuff->Tail = (ringbuff->Tail+1)%RINGBUFF_LEN;//·ÀÖ¹Ô½½ç·Ç·¨·ÃÎÊ
  ringbuff->Lenght++;
  return RINGBUFF_OK;
}

/**
* @brief  Read_RingBuff
* @param  uint8_t *rData£¬ÓÃÓÚ±£´æ¶ÁÈ¡µÄÊý¾Ý
* @return FLASE:>>·ÐÎ>>º³åÇøÃ>>ÓÐÊý¾Ý£¬¶Áȡʧ°Ü;TRUE:¶ÁÈ¡³É¹¦
* @note   ´Ó>>·ÐÎ>>º³åÇø¶ÁÈ¡Ò>>¸öu8ÀàÐ͵ÄÊý¾Ý
*/
uint8_t Read_RingBuff(RingBuff_t *ringbuff, uint8_t *rData)
{
  if(ringbuff->Lenght == 0)//ÅжϷǿÕ
  {
    return RINGBUFF_ERR;
  }
  *rData = ringbuff->Ring_data[ringbuff->Head];//ÏȽøÏȳöFIFO£¬´Ó>>º³åÇøÍ·³ö
  ringbuff->Head = (ringbuff->Head+1)%RINGBUFF_LEN;//·ÀÖ¹Ô½½ç·Ç·¨·ÃÎÊ
  ringbuff->Lenght--;
  return RINGBUFF_OK;
}

uart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "stm32f4xx_conf.h"
#include "sys.h" 

#define EN_USART1_RX 			1		//ʹÄÜ£¨1£©/½ûÖ¹£¨0£©´®¿Ú1½ÓÊÕ
	  	
#define  RINGBUFF_LEN          (100)     //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý
#define  RINGBUFF_OK           1     
#define  RINGBUFF_ERR          0   

typedef struct
{
    uint16_t Head;           
    uint16_t Tail;
    uint16_t Lenght;
    uint8_t  Ring_data[RINGBUFF_LEN];
}RingBuff_t;

extern uint8_t RecCoorFlag;
extern RingBuff_t Uart2_RingBuff,Uart1_RingBuff,Uart3_RingBuff;
extern uint16_t distance;

void uart_init(u32 bound);
void uart2_v831_init(uint32_t bound);
void uart3_init(uint32_t bound);
void usart_send(USART_TypeDef* USARTx, uint8_t*data, uint8_t len);

void RingBuff_Init(RingBuff_t *ringbuff);
uint8_t Write_RingBuff(RingBuff_t *ringbuff, uint8_t data);
uint8_t Read_RingBuff(RingBuff_t *ringbuff, uint8_t *rData);
uint8_t DataDecode(RingBuff_t *ringbuff, uint8_t *data1, uint8_t *data2);
int8_t receiveJson(RingBuff_t *ringbuff, char *str);

uint16_t get_distance(void);

#endif

2.spi

(1)原理

SPI协议使用四个信号线进行通信:主设备的主输出(MOSI),主输入(MISO),时钟线(SCK)和片选线(SS)。

  1. 主设备向从设备发送数据:主设备选中一个从设备,通过片选线SS将其选中。然后,主设备通过主输出线(MOSI)将数据发送给从设备。同时,主设备通过时钟线(SCK)提供时钟信号来同步数据传输。
  2. 主设备接收从设备的数据:主设备向从设备发送时钟信号,从设备通过主输入线(MISO)将数据传输给主设备。
  3. 数据传输完成后,主设备通过将片选线(SS)拉高来释放从设备。

SPI协议支持全双工通信,意味着主设备和从设备可以同时发送和接收数据。(同步通信、全双工通信方式)

(2)实际操作和注意事项

首先设置成主机模式,然后对于的io口初始化映射即可。设置单向或者双向数据模式、设置spi的数据大小、设置时钟线空闲时候的电平状态,设置数据采样方式,设定波特率,最后使能spi。(也是和uart一样需要将数据存放到一个固定的buff中,然后对其进行下一步的处理或者运用。)我们最常用的spi也就是7zhen0.96寸的oled。

(3)代码

spi.c

void SPI1_Init(void)
{	 
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//ʹÄÜGPIOBʱÖÓ
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//ʹÄÜSPI1ʱÖÓ
 
  //GPIOFB3,4,5³õʼ>>¯ÉèÖÃ
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5¸´Óù¦ÄÜÊä³ö	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ­
  GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ>>¯
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3¸´ÓÃΪ SPI1
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4¸´ÓÃΪ SPI1
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5¸´ÓÃΪ SPI1
 
	//ÕâÀïÖ>>Õë¶ÔSPI¿Ú³õʼ>>¯
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//¸´Î>>SPI1
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//Í£Ö¹¸´Î>>SPI1

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //ÉèÖÃSPIµ¥Ïò>>òÕßË<<ÏòµÄÊý¾Ýģʽ:SPIÉèÖÃΪË<<ÏßË<<ÏòÈ<<Ë<<¹¤
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//ÉèÖÃSPI¹¤×÷ģʽ:ÉèÖÃΪÖ÷SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//ÉèÖÃSPIµÄÊý¾Ý´óС:SPI·¢ËͽÓÊÕ8Î>>Ö¡½á¹¹
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//´®ÐÐͬ²½Ê±ÖӵĿÕÏÐ״̬Ϊ¸ßµçƽ
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//´®ÐÐͬ²½Ê±Öӵĵڶþ¸öÌø±äÑØ£¨ÉÏÉý>>òϽµ£©Êý¾Ý±>>²ÉÑù
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSSÐźÅÓÉÓ²¼þ£¨NSS¹Ü½Å£©>>¹ÊÇÈí¼þ£¨Ê¹ÓÃSSIÎ>>£©¹ÜÀí:ÄÚ²¿NSSÐźÅÓÐSSIÎ>>¿ØÖÆ
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//¶¨Ò岨ÌØÂÊÔ¤·ÖƵµÄÖµ:²¨ÌØÂÊÔ¤·ÖƵֵΪ256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//Ö¸¶¨Êý¾Ý´<<Êä´ÓMSBÎ>>>>¹ÊÇLSBÎ>>¿ªÊ¼:Êý¾Ý´<<Êä´ÓMSBÎ>>¿ªÊ¼
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRCÖµ¼ÆËãµÄ¶àÏîʽ
	SPI_Init(SPI1, &SPI_InitStructure);  //¸ù¾ÝSPI_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ>>¯ÍâÉèSPIx¼Ä´æÆ÷
 
	SPI_Cmd(SPI1, ENABLE); //ʹÄÜSPIÍâÉè

	SPI1_ReadWriteByte(0xff);//Æô¶¯´<<Êä		 
}   
//SPI1ËÙ¶ÈÉèÖú¯Êý
//SPIËÙ¶È=fAPB2/·ÖƵϵÊý
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  
//fAPB2ʱÖÓÒ>>°ãΪ84Mhz£º
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//ÅжÏÓÐЧÐÔ
	SPI1->CR1&=0XFFC7;//Î>>3-5ÇåÁ㣬ÓÃÀ´ÉèÖò¨ÌØÂÊ
	SPI1->CR1|=SPI_BaudRatePrescaler;	//ÉèÖÃSPI1ËÙ¶È 
	SPI_Cmd(SPI1,ENABLE); //ʹÄÜSPI1
} 
//SPI1 ¶ÁдÒ>>¸ö×Ö½Ú
//TxData:ҪдÈëµÄ×Ö½Ú
//·µ>>ØÖµ:¶ÁÈ¡µ½µÄ×Ö½Ú
u8 SPI1_ReadWriteByte(u8 TxData)
{		 			 
 
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//µÈ´ý·¢ËÍÇø¿Õ  
	
	SPI_I2S_SendData(SPI1, TxData); //ͨ¹ýÍâÉèSPIx·¢ËÍÒ>>¸öbyte  Êý¾Ý
		
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //µÈ´ý½ÓÊÕÍêÒ>>¸öbyte  
 
	return SPI_I2S_ReceiveData(SPI1); //·µ>>Øͨ¹ýSPIx×î½ü½ÓÊÕµÄÊý¾Ý	
 		    
}

spi.h

#ifndef __SPI_H
#define __SPI_H
#include "sys.h"

 	    													  
void SPI1_Init(void);			 //³õʼ>>¯SPI1¿Ú
void SPI1_SetSpeed(u8 SpeedSet); //ÉèÖÃSPI1ËÙ¶È   
u8 SPI1_ReadWriteByte(u8 TxData);//SPI1×ÜÏ߶ÁдÒ>>¸ö×Ö½Ú
		 
#endif

3.i2c

(1)原理

I2C 是一种串行通信协议,用于连接微控制器或其他集成电路之间的通信。I2C协议使用两个信号线进行通信:串行数据线(SDA)和串行时钟线(SCL)。

I2C的工作原理如下:

  1. 主设备发送数据:主设备先发送起始信号,即将SDA从高电平拉低,然后再将SCL拉高。接着,主设备通过SDA线发送地址和数据位,每一位都在SCL的上升沿或下降沿进行采样。
  2. 从设备接收数据:从设备在SCL的上升沿或下降沿采样SDA线上的数据位。
  3. 主设备接收数据:主设备将SDA线拉低并将SCL线拉高,从设备将数据位写到SDA线上。接着,主设备在SCL的上升沿或下降沿采样数据位。
  4. 数据传输完成后,主设备发送停止信号,即将SDA从低电平拉高,然后再将SCL拉高。

I2C协议支持多主设备,即多个主设备可以在总线上进行通信。每个设备都有唯一的地址,主设备通过地址选择要与之通信的设备。I2C协议的传输速度相对较慢,但适用于短距离通信。

(2)日常的使用

首先i2c分为软件I2C和硬件I2C在一般的日常使用是使用软件i2c,因为I2C不能连接太多的设备,不存在像spi那么多的io口,只有数据线和时钟线,软件代码部分就相对复杂一点。最开始还是需要io初始化映射,然后设置I2C的开始和停止信号,设置应答信号,最后进行数据的发送接收。

(3)代码

MPUIIC.C

#include "mpuiic.h"
#include "delay.h"

//MPU IIC ÑÓʱº¯Êý
void MPU_IIC_Delay(void)
{
	delay_us(2);
}

//³õʼ>>¯IIC
void MPU_IIC_Init(void)
{			
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//ÏÈʹÄÜÍâÉèIO PORTBʱÖÓ 
		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0;	 // ¶Ë¿ÚÅäÖÃ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 		 //ÍÆÍìÊä³ö
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO¿ÚËÙ¶ÈΪ50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);					 //¸ù¾ÝÉ趨²ÎÊý³õʼ>>¯GPIO 

	GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_0);				
 
}
//²úÉúIICÆðʼÐźÅ
void MPU_IIC_Start(void)
{
	MPU_SDA_OUT();     //sdaÏßÊä³ö
	MPU_IIC_SDA=1;	  	  
	MPU_IIC_SCL=1;
	MPU_IIC_Delay();
 	MPU_IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	MPU_IIC_Delay();
	MPU_IIC_SCL=0;//ǯסI2C×ÜÏߣ¬×¼±¸·¢ËÍ>>ò½ÓÊÕÊý¾Ý 
}	  
//²úÉúIICÍ£Ö¹ÐźÅ
void MPU_IIC_Stop(void)
{
	MPU_SDA_OUT();//sdaÏßÊä³ö
	MPU_IIC_SCL=0;
	MPU_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	MPU_IIC_Delay();
	MPU_IIC_SCL=1;  
	MPU_IIC_SDA=1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
	MPU_IIC_Delay();							   	
}
//µÈ´ýÓ¦´ðÐźŵ½À´
//·µ>>ØÖµ£º1£¬½ÓÊÕÓ¦´ðʧ°Ü
//        0£¬½ÓÊÕÓ¦´ð³É¹¦
u8 MPU_IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	MPU_SDA_IN();      //SDAÉèÖÃΪÊäÈë  
	MPU_IIC_SDA=1;MPU_IIC_Delay();	   
	MPU_IIC_SCL=1;MPU_IIC_Delay();	 
	while(MPU_READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			MPU_IIC_Stop();
			return 1;
		}
	}
	MPU_IIC_SCL=0;//ʱÖÓÊä³ö0 	   
	return 0;  
} 
//²úÉúACKÓ¦´ð
void MPU_IIC_Ack(void)
{
	MPU_IIC_SCL=0;
	MPU_SDA_OUT();
	MPU_IIC_SDA=0;
	MPU_IIC_Delay();
	MPU_IIC_SCL=1;
	MPU_IIC_Delay();
	MPU_IIC_SCL=0;
}
//²>>²úÉúACKÓ¦´ð		    
void MPU_IIC_NAck(void)
{
	MPU_IIC_SCL=0;
	MPU_SDA_OUT();
	MPU_IIC_SDA=1;
	MPU_IIC_Delay();
	MPU_IIC_SCL=1;
	MPU_IIC_Delay();
	MPU_IIC_SCL=0;
}					 				     
//IIC·¢ËÍÒ>>¸ö×Ö½Ú
//·µ>>Ø´Ó>>úÓÐÎÞÓ¦´ð
//1£¬ÓÐÓ¦´ð
//0£¬ÎÞÓ¦´ð			  
void MPU_IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	MPU_SDA_OUT(); 	    
    MPU_IIC_SCL=0;//À­µÍʱÖÓ¿ªÊ¼Êý¾Ý´<<Êä
    for(t=0;t<8;t++)
    {              
        MPU_IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		MPU_IIC_SCL=1;
		MPU_IIC_Delay(); 
		MPU_IIC_SCL=0;	
		MPU_IIC_Delay();
    }	 
} 	    
//¶Á1¸ö×Ö½Ú£¬ack=1ʱ£¬·¢ËÍACK£¬ack=0£¬·¢ËÍnACK   
u8 MPU_IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	MPU_SDA_IN();//SDAÉèÖÃΪÊäÈë
    for(i=0;i<8;i++ )
	{
        MPU_IIC_SCL=0; 
        MPU_IIC_Delay();
		MPU_IIC_SCL=1;
        receive<<=1;
        if(MPU_READ_SDA)receive++;   
		MPU_IIC_Delay(); 
    }					 
    if (!ack)
        MPU_IIC_NAck();//·¢ËÍnACK
    else
        MPU_IIC_Ack(); //·¢ËÍACK   
    return receive;
}

MPUIIC.H

#ifndef __MPUIIC_H
#define __MPUIIC_H
#include "sys.h"
/
//IO·½ÏòÉèÖÃ

#define MPU_SDA_IN()  {GPIOA->MODER&=~(3<<(1*2));GPIOA->MODER|=0<<1*2;}	//PA1ÊäÈëģʽ
#define MPU_SDA_OUT() {GPIOA->MODER&=~(3<<(1*2));GPIOA->MODER|=1<<1*2;} //PA1Êä³öģʽ



//IO²Ù×÷º¯Êý	 
#define MPU_IIC_SCL     PAout(0) //SCL
#define MPU_IIC_SDA     PAout(1) //SDA	
#define MPU_READ_SDA   	PAin(1) //SDA	




//IICËùÓвÙ×÷º¯Êý
void MPU_IIC_Delay(void);				//MPU IICÑÓʱº¯Êý
void MPU_IIC_Init(void);                //³õʼ>>¯IICµÄIO¿Ú				 
void MPU_IIC_Start(void);				//·¢ËÍIIC¿ªÊ¼ÐźÅ
void MPU_IIC_Stop(void);	  			//·¢ËÍIICÍ£Ö¹ÐźÅ
void MPU_IIC_Send_Byte(u8 txd);			//IIC·¢ËÍÒ>>¸ö×Ö½Ú
u8 MPU_IIC_Read_Byte(unsigned char ack);//IIC¶ÁÈ¡Ò>>¸ö×Ö½Ú
u8 MPU_IIC_Wait_Ack(void); 				//IICµÈ´ýACKÐźÅ
void MPU_IIC_Ack(void);					//IIC·¢ËÍACKÐźÅ
void MPU_IIC_NAck(void);				//IIC²>>·¢ËÍACKÐźÅ

void IMPU_IC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 MPU_IIC_Read_One_Byte(u8 daddr,u8 addr);	  

#endif
相关推荐
言、雲1 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
OopspoO5 分钟前
qcow2镜像大小压缩
学习·性能优化
不过四级不改名6776 分钟前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普26 分钟前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣29 分钟前
单片机UDP数据透传
单片机·嵌入式硬件·udp
A懿轩A29 分钟前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
汪洪墩30 分钟前
【Mars3d】设置backgroundImage、map.scene.skyBox、backgroundImage来回切换
开发语言·javascript·python·ecmascript·webgl·cesium
云空36 分钟前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
Anna。。38 分钟前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
居居飒38 分钟前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin