BG Development


Страници: (5) [1] 2 3 ... последна »  ( Първото ново мнение ) Reply to this topicStart new topicStart Poll

> Малко микроконтролер-програмиране, и2ц бус
ProgramGuro
Публикувано на: 06-07-2017, 12:39
Quote Post



Име:
Група: Потребител
Ранг: Новопостъпил

Мнения: 2
Регистриран на: 06.07.17



Здравейте всички, искам да споделя със всички от вас които се интересуват от програмиране на микроконтролери една възможност, как да напишете и2ц код. За тези които не са запознати, и2ц бус е възможност да свържете голям брой сенсори или подобни устройства към един микроконролер само с помощта на 2 връзки, като не броим захранването. Това са: Часовник (или такт) и разбирасе Данни.
Ето го и кода:
CODE

# include <DrvI2C.h>

# include <STM32F4xx_init.h>
# include <Drv9DOF_Sensor.h>
# include <RB_NVIC.h>
# include <RB_I2C.h>
# include <RB_RCC.h>
# include <RB.h>



typedef struct {
 RegbankTypeI2C volatile * ptr2RegBank;
 unsigned peripheryNum;
 unsigned interruptNum_1;
 unsigned interruptNum_2;
} I2C_Constants_Type;


struct __I2C_Descriptor
{
 I2C_Constants_Type const* ptr2Constants;
 I2C_Parameter_Type_read  * I2C_Parameter_read;    
 I2C_Parameter_Type_write * I2C_Parameter_write;  
 unsigned volatile write_pos;                      
 unsigned volatile read_pos;                      
 unsigned int  i2c_counter;                      
 unsigned char I2C_Status;                        
 unsigned char I2C_Modus;                          
};


static I2C_Constants_Type const I2C1_Constants = { &rbI2C1, PERIPHERY_APB_I2C1, EXTIRQ_I2C1_EV, EXTIRQ_I2C1_ER };

static I2C_Constants_Type const I2C2_Constants = { &rbI2C2, PERIPHERY_APB_I2C2, EXTIRQ_I2C2_EV, EXTIRQ_I2C2_ER };
static I2C_Constants_Type const I2C3_Constants = { &rbI2C3, PERIPHERY_APB_I2C3, EXTIRQ_I2C3_EV, EXTIRQ_I2C3_ER };


static I2C_DescriptorType descrArray[] = {
 { &I2C1_Constants, 0, 0, 0U, 0U, 0U, I2C_READY, 0U },
 { &I2C2_Constants, 0, 0, 0U, 0U, 0U, I2C_READY, 0U },
 { &I2C3_Constants, 0, 0, 0U, 0U, 0U, I2C_READY, 0U },
};



void I2C_init(I2CType I2C_number)
{

 I2C_Constants_Type const * const theConstants = descrArray[I2C_number].ptr2Constants;

 RegbankTypeI2C volatile * const ptr2I2C = descrArray[I2C_number].ptr2Constants->ptr2RegBank;
 

 unsigned fregMHz = (PClk1()/1000000U);
 
 
 APBClockEnable(theConstants->peripheryNum);
 

 ptr2I2C->CR1    = 0;
 // enable eventinterrupt und error interrupt
 ptr2I2C->CR2    = fregMHz | MASK_I2C_CR2_ITEVTEN | MASK_I2C_CR2_ITERREN;
 ptr2I2C->CCR    = fregMHz*5;
 ptr2I2C->TRISE  = fregMHz+1;
 /// Peripherie enable
 ptr2I2C->CR1    = MASK_I2C_CR1_PE;

 /// EVENT Interrupt freischalten
 InterruptEnable(theConstants->interruptNum_1);
 
 /// ERROR Interrupt freischalten
 InterruptEnable(theConstants->interruptNum_2);
 
}



void IRQ_I2C1_EV ( void )
{

 descrArray[I2C1].i2c_counter++;
 
 switch(descrArray[I2C1].I2C_Modus)
 {
   case I2C_READ:     I2C_Read(&descrArray[I2C1]);
                       break;
   case I2C_WRITE:    I2C_Write(&descrArray[I2C1]);
                       break;
 }
}


void IRQ_I2C1_ER (void)
{  
   I2C_error(descrArray[I2C1].ptr2Constants->ptr2RegBank->SR1, &descrArray[I2C1]);
   ITM_PUTS("ERROR INTERRUPT");
   reset_phase();
}




void disable_RXNE_TXE(I2C_HandleType I2C_Handle)
{
 I2C_Handle->ptr2Constants->ptr2RegBank->CR2   &= ~MASK_I2C_CR2_ITBUFEN;  
}


void enable_RXNE_TXE(I2C_HandleType I2C_Handle)
{
 I2C_Handle->ptr2Constants->ptr2RegBank->CR2   |=  MASK_I2C_CR2_ITBUFEN;
}


void reset_ADDR (I2C_HandleType I2C_Handle)
{
 HWRD Status_Register_2 = I2C_Handle->ptr2Constants->ptr2RegBank->SR2;
}


void reset_BTF (I2C_HandleType I2C_Handle)
{
 I2C_Handle->ptr2Constants->ptr2RegBank->DR = 0;
}


void I2C_ack(I2C_HandleType I2C_Handle)
{
 I2C_Handle->ptr2Constants->ptr2RegBank->CR1 |= MASK_I2C_CR1_ACK;
}


void I2C_nack(I2C_HandleType I2C_Handle)
{
 I2C_Handle->ptr2Constants->ptr2RegBank->CR1 &= ~MASK_I2C_CR1_ACK;
}


void I2C_start(I2C_HandleType I2C_Handle)
{
 
 I2C_Handle->ptr2Constants->ptr2RegBank->CR1 |= MASK_I2C_CR1_START;

}


void I2C_stop(I2C_HandleType I2C_Handle)
{
 
 I2C_Handle->ptr2Constants->ptr2RegBank->CR1   |= MASK_I2C_CR1_STOP;
}


void I2C_disable(I2C_HandleType I2C_Handle)
{
 
 I2C_Handle->ptr2Constants->ptr2RegBank->CR1    &= ~MASK_I2C_CR1_PE;
 
}


I2C_ErrCodeType WriteByte(I2C_HandleType I2C_Handle)
{              
 
 if ((I2C_Handle->write_pos == I2C_Handle->I2C_Parameter_write->number_of_bytes) && (I2C_Handle->I2C_Modus == I2C_WRITE) )
 {
   I2C_Handle->write_pos = 0;
   return error;
 }
      I2C_Handle->ptr2Constants->ptr2RegBank->DR = I2C_Handle->I2C_Parameter_write->buffer_send[I2C_Handle->write_pos];
 
 I2C_Handle->write_pos++;
 return no_error;
}      


void ReStartFunc(I2C_HandleType I2C_Handle)
{            
       I2C_stop(I2C_Handle);
       reset_BTF(I2C_Handle);
       I2C_start(I2C_Handle);
       
       if ((I2C_Handle->I2C_Parameter_read->number_of_bytes > 1) && (I2C_Handle->I2C_Modus  == I2C_READ))
         I2C_ack(I2C_Handle);
}



I2C_ErrCodeType DataReadFunc( I2C_HandleType I2C_Handle )
{            

 
     if (I2C_Handle->read_pos == (I2C_Handle->I2C_Parameter_read->number_of_bytes-1))
     {
       disable_RXNE_TXE(I2C_Handle);
       I2C_Handle->I2C_Parameter_read->buffer_recv[I2C_Handle->read_pos] = I2C_Handle->ptr2Constants->ptr2RegBank->DR;
       I2C_stop(I2C_Handle);
       I2C_Handle->ptr2Constants->ptr2RegBank->DR = 0;
       
       I2C_Handle->i2c_counter = 0;
       I2C_Handle->write_pos   = 0;
       I2C_Handle->read_pos    = 0;      
       return end_of_transfer;
     }

     else if (I2C_Handle->read_pos == (I2C_Handle->I2C_Parameter_read->number_of_bytes-2))
     {
       I2C_Handle->I2C_Parameter_read->buffer_recv[I2C_Handle->read_pos] = I2C_Handle->ptr2Constants->ptr2RegBank->DR;
       I2C_nack(I2C_Handle);    
     }
     else if (I2C_Handle->read_pos < (I2C_Handle->I2C_Parameter_read->number_of_bytes-1))
     {
             
       I2C_Handle->I2C_Parameter_read->buffer_recv[I2C_Handle->read_pos] = I2C_Handle->ptr2Constants->ptr2RegBank->DR;
       I2C_ack(I2C_Handle);  
     }
     I2C_Handle->i2c_counter--;
     I2C_Handle->read_pos++;
     return no_error;
}



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


void I2C_Read(I2C_HandleType I2C_Handle)
{
 
   HWRD  const Status_Register_1 = I2C_Handle->ptr2Constants->ptr2RegBank->SR1;  
   switch (I2C_Handle->i2c_counter)
   {
     case Write_First_Byte:  if (Status_Register_1 & MASK_I2C_SR1_SB)
                               WriteByte(I2C_Handle);
                             else
                               I2C_error(Status_Register_1, I2C_Handle);
                             break;
     case Write_Sec_Byte:    if((Status_Register_1 & MASK_I2C_SR1_ADDR) && (Status_Register_1 & MASK_I2C_SR1_TXE))  //ADDR wird gelöscht durch Lesen des SR1 und SR2
                             {
                               reset_ADDR(I2C_Handle);
                               WriteByte(I2C_Handle);
                             }
                             else
                               I2C_error(Status_Register_1, I2C_Handle);
                             break;
     case Repeated_Start:    if (Status_Register_1 & MASK_I2C_SR1_BTF)
                               ReStartFunc(I2C_Handle);
                             else
                               I2C_error(Status_Register_1, I2C_Handle);
                             break;
     case Write_Third_Byte:  if (Status_Register_1 & MASK_I2C_SR1_SB)
                               WriteByte(I2C_Handle);
                             else
                               I2C_error(Status_Register_1, I2C_Handle);
                             break;
     case RXNE_Enable:       if (Status_Register_1 & MASK_I2C_SR1_ADDR)
                             {
                               reset_ADDR(I2C_Handle);
                               enable_RXNE_TXE(I2C_Handle);
                             }
                             else
                               I2C_error(Status_Register_1, I2C_Handle);                                  
                             break;
     case Receive_Byte:      if (Status_Register_1 & MASK_I2C_SR1_RXNE)  
                             {
                               char errcode = DataReadFunc(I2C_Handle);
                               if(errcode == end_of_transfer)
                                 I2C_Handle->I2C_Status = I2C_READY;
                               else if (errcode == error)
                                 I2C_error(Status_Register_1, I2C_Handle);
                             }
                             else
                               I2C_error(Status_Register_1, I2C_Handle);
                             break;      
     default:                I2C_error(Status_Register_1, I2C_Handle);
                             break;
   }
}


void I2C_Write(I2C_HandleType I2C_Handle)
{

   HWRD  const Status_Register_1 = I2C_Handle->ptr2Constants->ptr2RegBank->SR1;  
   switch (I2C_Handle->i2c_counter)
   {
     case Write_First_Byte:      if (Status_Register_1 & MASK_I2C_SR1_SB)
                                   WriteByte(I2C_Handle);
                                 else
                                   I2C_error(Status_Register_1, I2C_Handle);
                                 break;
     case Write_Sec_Byte:        if ((Status_Register_1 & MASK_I2C_SR1_ADDR) && (Status_Register_1 & MASK_I2C_SR1_TXE))  //ADDR
                                 {
                                   reset_ADDR(I2C_Handle);
                                   enable_RXNE_TXE(I2C_Handle);
                                   WriteByte(I2C_Handle);
                                 }
                                 else
                                   I2C_error(Status_Register_1, I2C_Handle);
                                 break;
     case Write_all_Bytes:       if (Status_Register_1 & MASK_I2C_SR1_TXE)
                                 {
                                   WriteByte(I2C_Handle);
                                   if (I2C_Handle->I2C_Parameter_write->number_of_bytes == I2C_Handle->write_pos)
                                     disable_RXNE_TXE(I2C_Handle);
                                   else if (I2C_Handle->I2C_Parameter_write->number_of_bytes != I2C_Handle->write_pos)
                                     I2C_Handle->i2c_counter--;
                                 }
                                 else
                                   I2C_error(Status_Register_1, I2C_Handle);
                                 break;  
     case Finish_Transmission:   if (Status_Register_1 & MASK_I2C_SR1_BTF)
                                 {
                                   I2C_stop(I2C_Handle);
                                   reset_BTF(I2C_Handle);
                                   I2C_Handle->i2c_counter = 0;
                                   I2C_Handle->write_pos   = 0;
                                   I2C_Handle->read_pos    = 0;
                                   I2C_Handle->I2C_Status  = I2C_READY;
                                 }      
                                 else
                                   I2C_error(Status_Register_1, I2C_Handle);
                                 
                                 break;        
     default:                    I2C_error(Status_Register_1, I2C_Handle);
                                 break;
   }
}





void I2C_error(HWRD  const Status_Register_1,I2C_HandleType I2C_Handle)
{
 I2C_stop(I2C_Handle);
 disable_RXNE_TXE(I2C_Handle);
 reset_BTF(I2C_Handle);
 RegbankTypeI2C volatile * const ptr2I2C = I2C_Handle->ptr2Constants->ptr2RegBank;
 
 if (Status_Register_1 & MASK_I2C_SR1_ARLO)
 {
   ptr2I2C->SR1 &= ~MASK_I2C_SR1_ARLO;
   ITM_PUTS("I2C: Arbitration Lost");
 }
 if (Status_Register_1 & MASK_I2C_SR1_AF)
 {
   ptr2I2C->SR1 &= ~MASK_I2C_SR1_AF;  
   ITM_PUTS("I2C: Acknowlege Failure");
 }  
 if (Status_Register_1 & MASK_I2C_SR1_BERR)
 {
   ptr2I2C->SR1 &= ~MASK_I2C_SR1_BERR;
   ITM_PUTS("I2C: Buss Error");
 }  
 if (Status_Register_1 & MASK_I2C_SR1_OVR)
 {
   ptr2I2C->SR1 &= ~MASK_I2C_SR1_OVR;
   ITM_PUTS("I2C: Overrun/Underrun");
 }  
 if (Status_Register_1 & MASK_I2C_SR1_PECERR)
 {
   ptr2I2C->SR1 &= ~MASK_I2C_SR1_PECERR;
   ITM_PUTS("I2C: Packet Error Checking: NACK after PEC reception");
 }  
 I2C_Handle->I2C_Status = I2C_READY; // freigeben des I2C Bus
 char *buffer;
 switch(I2C_Handle->I2C_Modus)
 {
   case I2C_READ:  buffer = "I2C_READ";
                 break;
   case I2C_WRITE: buffer = "I2C_WRITE";
                 break;
 }
 ITM_PRINTF("Error der Funktion \"%s\" im Case %d.\nStatus-Register:0x%04X",buffer, I2C_Handle->i2c_counter, Status_Register_1);
 ITM_PRINTF(" Bytes:%d",I2C_Handle->write_pos);  
 ITM_PRINTF("Bytes:%d",I2C_Handle->read_pos);  
 
 I2C_Handle->i2c_counter = 0;
 I2C_Handle->write_pos   = 0;
 I2C_Handle->read_pos    = 0;
}



void I2C_Start_read_Communication(I2CType I2C_number, I2C_Parameter_Type_read * I2C_Data, I2C_Parameter_Type_write * I2C_Param)
{


 if (descrArray[I2C_number].I2C_Status == I2C_READY)
 {
   descrArray[I2C_number].I2C_Modus           = I2C_READ;
   descrArray[I2C_number].I2C_Status          = I2C_PROCESS;
   descrArray[I2C_number].I2C_Parameter_read  = I2C_Data;      
   descrArray[I2C_number].I2C_Parameter_write = I2C_Param;    
   I2C_start(&descrArray[I2C_number]);    
 }
 else
 {
   I2C_error(0x1000, &descrArray[I2C_number]);
   ITM_PUTS("I2C war noch nicht fertig");  
 }
 
}



void I2C_Start_write_Communication(I2CType I2C_number, I2C_Parameter_Type_write * I2C_Param)
{



 if (descrArray[I2C_number].I2C_Status == I2C_READY)
 {
   descrArray[I2C_number].I2C_Modus           = I2C_WRITE;
   descrArray[I2C_number].I2C_Status          = I2C_PROCESS;
   descrArray[I2C_number].I2C_Parameter_write = I2C_Param;  
   I2C_start(&descrArray[I2C_number]);    
 }
 else
 {
   I2C_error(0, &descrArray[I2C_number]);
   ITM_PUTS("I2C war noch nicht fertig");  
 }
 
}


unsigned char Check_I2C_Status(I2CType I2C_number)
{
 return descrArray[I2C_number].I2C_Status;
}


void set_I2C_Status(unsigned char errcode, I2CType I2C_number)
{
 descrArray[I2C_number].I2C_Status = errcode;
}


Това мнение е било редактирано от DarkOne на 06-07-2017, 13:24
PMEmail Poster
Top
Bender
Публикувано на: 06-07-2017, 12:49
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4724
Регистриран на: 19.06.14



Нов тип трол ? Тоя прилича на онзи трол от TheWitcher 3 lol


--------------------
Живота е спагети, кода за да работи добре трябва да го наподобява - Дон Реба
...
Живеем в греховни времена, какво очакваш богоугоден и благочестив код ли? - Дон Реба
...
много положителна енергия черпя от вас двамата,единият комунистически девствен,другият яко яхнал асемблерните розови понита - saruman
...
Рано или късно усерите на Виндофс разбират че стоят от неправилната страна на хуя. - ici
PM
Top
ici
Публикувано на: 06-07-2017, 14:24
Quote Post


Group Icon
Име: Ивайло Илчев ики
Група: VIP
Ранг: Почетен член

Мнения: 14835
Регистриран на: 06.06.04



Какво да го правим този код без съответните .h файлове?
Защо да не използваме HAL от Stm? Stm32cubeFxx?
Дали тази библиотека поддържа fast i2c/i2c във stm32f4 или универсалните i2c във stm32f7?

Това мнение е било редактирано от ici на 06-07-2017, 14:24


--------------------
Everything you can imagine is real. Pablo Picasso
PMEmail PosterUsers Website
Top
ProgramGuro
Публикувано на: 07-07-2017, 11:03
Quote Post



Име:
Група: Потребител
Ранг: Новопостъпил

Мнения: 2
Регистриран на: 06.07.17



Всички променливи в кода са с умишлено подбрани имена, за да бъде лесно разбрано какво се крие зад тях. С помощта на "Manual" на съответния контролер могат лесно да бъдат написани и хедарите. Постнах този код, за да помогна на някой кото може би се интересува как може да бъде програмирана съответната и2ц комуникацич без графичен софтуер (CubeMX) и без безброй добавени библиотеки.
Реших, че просто на някой може да му е интересно и полезно
PMEmail Poster
Top
ici
Публикувано на: 07-07-2017, 11:47
Quote Post


Group Icon
Име: Ивайло Илчев ики
Група: VIP
Ранг: Почетен член

Мнения: 14835
Регистриран на: 06.06.04





--------------------
Everything you can imagine is real. Pablo Picasso
PMEmail PosterUsers Website
Top
bvbfan
Публикувано на: 07-07-2017, 12:21
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 2409
Регистриран на: 08.12.13



Колкото и бърз да е random access-а на C array (по-бърз няма) все пак може да си пребуферираш descrArray[I2C_number] да не достъпваш всеки път.


--------------------
QUOTE (Bender @ 23-04-2015, 19:11)
Xamarin: ЛАПАЙ!
Ти: Добре...
PMEmail Poster
Top
Dr.Who
Публикувано на: 07-07-2017, 12:36
Quote Post



Име:
Група: Потребител
Ранг: Активен

Мнения: 283
Регистриран на: 25.05.14



QUOTE (bvbfan @ 07-07-2017, 12:21)
Колкото и бърз да е random access-а на C array (по-бърз няма) все пак може да си пребуферираш descrArray[I2C_number] да не достъпваш всеки път.

Разочарован съм от това мнение.
Очаквах минимум да напишеш, че трябва да го пренапише на C++,
понеже всички спецове казват, че С++11 е по-добро за ембедед от С
PMEmail Poster
Top
kierenski
Публикувано на: 07-07-2017, 13:18
Quote Post



Име:
Група: Потребител
Ранг: Посетител

Мнения: 113
Регистриран на: 10.01.16



QUOTE (Dr.Who @ 07-07-2017, 12:36)
QUOTE (bvbfan @ 07-07-2017, 12:21)
Колкото и бърз да е random access-а на C array (по-бърз няма) все пак може да си пребуферираш descrArray[I2C_number] да не достъпваш всеки път.

Разочарован съм от това мнение.
Очаквах минимум да напишеш, че трябва да го пренапише на C++,
понеже всички спецове казват, че С++11 е по-добро за ембедед от С

C++ и като цяло обектното програмиране никога не е било добро за писане на драйвери и комуникация на ниско ниво(защото чистото C е по-близо до асемблер), но за разлика от това си има големи предимства и много по-лесно стават нещата там където се иска по-голяма подреденост и не толкова скорост като при графичните среди и игрите.
PMEmail Poster
Top
dvader
Публикувано на: 07-07-2017, 15:12
Quote Post


Group Icon
Име:
Група: VIP
Ранг: Почетен член

Мнения: 3697
Регистриран на: 12.07.05



QUOTE (kierenski @ 07-07-2017, 13:18)
защото чистото C е по-близо до асемблер

Сега ще се тролиме ли, какво ли...


--------------------
I find your lack of faith disturbing
PM
Top
Реконструктор
Публикувано на: 07-07-2017, 15:25
Quote Post



Име:
Група: Потребител
Ранг: Активен

Мнения: 224
Регистриран на: 18.12.06



QUOTE (kierenski @ 07-07-2017, 13:18)
QUOTE (Dr.Who @ 07-07-2017, 12:36)
QUOTE (bvbfan @ 07-07-2017, 12:21)
Колкото и бърз да е random access-а на C array (по-бърз няма) все пак може да си пребуферираш descrArray[I2C_number] да не достъпваш всеки път.

Разочарован съм от това мнение.
Очаквах минимум да напишеш, че трябва да го пренапише на C++,
понеже всички спецове казват, че С++11 е по-добро за ембедед от С

C++ и като цяло обектното програмиране никога не е било добро за писане на драйвери и комуникация на ниско ниво(защото чистото C е по-близо до асемблер), но за разлика от това си има големи предимства и много по-лесно стават нещата там където се иска по-голяма подреденост и не толкова скорост като при графичните среди и игрите.

Не става въпрос за добро/лошо ами за безсмислено. ООП в ембедед среда е просто безсмислено.
PMEmail Poster
Top
1 потребители преглеждат тази тема в момента (1 гости, 0 анонимни потребители)
Потребители, преглеждащи темата в момента:

Topic Options Страници: (5) [1] 2 3 ... последна » Reply to this topicStart new topicStart Poll

 


Copyright © 2003-2015 | BG Development | All Rights Reserved
RSS 2.0