Merhaba, uzun zaman oldu ne bloğuma nede kendime pek zaman ayıramıyorum bu aralar. Sebep belkide motosikletimi satmış olmam olabilir.
Malum bir hexapod işine girdim yazıyı takip ediyorsunuzdur diye umuyorum. Projede kullanılacak olan 18 adet RC servo yu kullanabilmek için 18, 20ms lik peryoda sahip pwm in üretilmesi gerekiyor. bunu doğrudan stm32f4discovery kitten alabilirim. ama bu bana 18 adet pin in buraya ayrılması demektir ki yokluk gören 8051 ile 16f84 ile çalışmak zorunda kalan bizim kuşak için pek uygun olmaz.
Aramalarım sonucu TI nin PWM Led driver nın bu iş için uygun olacağını düşündüm. Örnekleride bolca mevcut ama genelde Ardunio (hep yanlış yazarım şimdide doğrumu yanlış mı bilmiyorum) . Bu PWM sürücülerden iki çeşidini denedim TLC5947 ve TLC5940. İkisi arasındaki farklar aşağıda sıralanmıştır.
TLC5940 | TLC5947 | |
Data Vin (Min) (V) | 3 | 3 |
Data Vin (Max) (V) | 5.5 | 5.5 |
Output Channels | 16 | 24 |
Analog Dimming Steps | 64 | |
Data Input | Serial | Serial |
Data Transfer Rate (Typ) (MHz) | 30 | 30 |
Ch to Ch Accuracy (Typ) (+/- %) | 1 | 2 |
Per Channel PWM Steps | 4096 | 4096 |
Per Channel Drive (mA) | 120 | 30 |
LED Voltage (Max) (V) | 17 | 30 |
Special Features | Fault Reporting | Internal GS Clock |
LED Open Detection | Thermal Shutdown | |
Power Good/Error Flag | ||
Operating Temperature Range (C) | -40 to 85 | -40 to 85 |
iki sürücüyü birbirinden ayıran fark, kanal sayıları ve PWM in üretilmesi için gerekli olan GSCLK in internal yada external olmasıdır. Benim projemde 50hz lik bir Pwm e ihtiyaç duyduğumdan tlc 5940 seçmiş bulunmaktayım.
Aşağıda kodları verilen sürücü ile ilk etapta 50hz lik bir pwm oluşturmadım. Basitce SPI arayüzünden bilgileri gönderdim ve GSCLK üreteke bu PWM i çıkıştaki ledlerde gözlemledim.
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 |
#include <stm32f4xx.h> #include <stm32f4xx_rcc.h> #include <stm32f4xx_gpio.h> #include <stm32f4xx_tim.h> #include <stm32f4xx_spi.h> #include <misc.h> #define TLC_RCC_AHB1 RCC_AHB1Periph_GPIOB #define TLC5940_GPIO GPIOB #define PIN_BLANK GPIO_Pin_5 #define PIN_VPRG GPIO_Pin_9 #define PIN_XLAT GPIO_Pin_6 #define PIN_GSCLK GPIO_Pin_3 int timer_update=0; #define COUNT_TLC 1 void init_tim7(void){ TIM_TimeBaseInitTypeDef TIM_TBInitStruct; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM7EN,ENABLE); // Timer saat kaynağını aç TIM_TBInitStruct.TIM_Prescaler =8299; // ÖnBölücü (PSC) değeri 4199 TIM_TBInitStruct.TIM_Period =9; // Otomatik geri yükleme (ARR) eşiği 1 TIM_TimeBaseInit(TIM7,&TIM_TBInitStruct); // Timeri init et TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); // Timer Update olayında interrupt istesin. NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM7, ENABLE);// Timeri başlat } void TIM7_IRQHandler(void){ TIM7->SR=0; GPIOD->ODR ^= GPIO_Pin_12; timer_update +=1; } void init_SPI1(void){ GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD| TLC_RCC_AHB1, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOD, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(TLC5940_GPIO, &GPIO_InitStruct); /* configure pins used by SPI1 * PA5 = SCK * PA6 = MISO * PA7 = MOSI */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); // connect SPI1 pins to SPI alternate function GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); /* Configure the chip select pin in this case we will use PE7 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOE, &GPIO_InitStruct); GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high // enable peripheral clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* configure SPI1 in Mode 0 * CPOL = 0 --> clock is low when idle * CPHA = 0 --> data is sampled at the first edge */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // SPI frequency is APB2 frequency / 4 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); // enable SPI1 } /* This funtion is used to transmit and receive data * with SPI1 * data --> data to be transmitted * returns received value */ uint8_t SPI1_send(uint8_t data){ SPI_I2S_SendData(SPI1,data); //SPI1->DR = data; // write data to be transmitted to the SPI data register while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore return SPI1->DR; // return received data from SPI data register } void _delay(int value){ while(value--) { } } void Blank_Pulse(){ GPIO_SetBits(TLC5940_GPIO,PIN_BLANK); GPIO_ResetBits(TLC5940_GPIO,PIN_BLANK); //TLC5940_GPIO->ODR |=BLANK_PIN; //TLC5940_GPIO->ODR &=0x00000000; } void Xlat_Pulse(){ GPIO_SetBits(TLC5940_GPIO,PIN_XLAT); GPIO_ResetBits(TLC5940_GPIO,PIN_XLAT); //TLC5940_GPIO->ODR |=XLAT_PIN; //TLC5940_GPIO->ODR &=0x00000000; } void GSCLK_Pulse(){ GPIO_SetBits(TLC5940_GPIO,PIN_GSCLK); GPIO_ResetBits(TLC5940_GPIO,PIN_GSCLK); //TLC5940_GPIO->ODR |=GSCLK_PIN; //TLC5940_GPIO->ODR &=0x00000000; } //CHECK CORE CLK void MCO2_INIT(){ GPIO_InitTypeDef GPIO_InitStructure; // Output HSE clock (8 MHz) on MCO pin (PC9) RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO2Div_5); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO); } int main(void){ SystemInit(); //168mhz init_tim7(); init_SPI1(); MCO2_INIT(); uint_fast8_t n; //LED0 u16 data[COUNT_TLC* 16]={0x0000 ,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; GPIO_ResetBits(TLC5940_GPIO,PIN_VPRG); while(1){ GPIO_SetBits(GPIOD,GPIO_Pin_12); while(timer_update>3){ data[15] +=16; data[14] -=16; if (data[15]>4095) { data[15]=0; } GPIO_SetBits(TLC5940_GPIO,PIN_BLANK); for(n=0; n<(COUNT_TLC* 16); n=n+2) { SPI1_send(data[n]>>4); SPI1_send((data[n]<<4) | (data[n+1])>>8); SPI1_send(data[n+1]); } GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high GPIO_ResetBits(GPIOD,GPIO_Pin_12); GPIOE->BSRRH |= GPIO_Pin_7; _delay(1); GPIO_SetBits(TLC5940_GPIO,PIN_XLAT); _delay(1); GPIO_ResetBits(TLC5940_GPIO,PIN_BLANK); GPIO_ResetBits(TLC5940_GPIO,PIN_XLAT); _delay(1); timer_update=0; } int i; //generate GSCLK for (i = 0; i < 4096; i++){ TLC5940_GPIO->BSRRL = PIN_GSCLK; TLC5940_GPIO->BSRRH = PIN_GSCLK; } Blank_Pulse(); } } |