Cümleten selamün aleyküm,

Çok geçmeden yine bir yazı ile karşınızdayım. Uart üzerinden veri gönderimini gerçekleştirdikten sonra sıradaki kullanmak istediğim birim tabiki ADC birimi idi. Ama bunun için öncesinde uart birimini çalıştırmam gerekti. Çünkü ADC ile elde ettiğim verileri uart üzerinden bilgisayara gönderdim. Böylece elde ettiğim verileri gözlemleyebildim.

Uygulama Hakkında

Bildiğiniz/bilediğiniz gibi STM32F0 denetleyicimiz 12 bit ADC’ye sahip. Aynı zamanda daha düşük bit değerlerini destekliyor. Neyse 12 bit için buda demek oluyor ki ADC’den aldığımı sayısal değerler 0-4095 arasında olacak. Tamam ADC çevrim işlemini yaptık peki değeri nasıl göreceğiz? Değeri bir LCD’de bir ekranda vs. bir yerde görmek lazım ki uygulamanın çalıştığını anlayalım, içimiz rahat etsin. Malum kullandığım kartta LCD, ekran vs. bir şey olmadığı için(Zaten olsa bile onu asm ile kullanmak başı başına bir yazı konusu olurdu.) en mantıklı olarak okuduğum ADC değerlerini uart üzerinden bilgisayara gönderdim. Terminal programı üzerinden verileri gözlemledim. Tabi göndermeden önce 0-4095 arasında değişen ADC değerlerini basamaklarına ayırıp yani BCD koda çevirip sonrasında ASCII karaktere çevirip 4 basamağı ayrı ayrı karakter olarak göndermek gerekti. Bunun içinde öncelikle 4 basamağa kadar olan sayıları(0-9999) BCD koda çeviren bir alt program yazdım. Basamaklarına ayırma işleminin temelinde bölme işlemi olduğundan ve cortex-m0 işlemcimiz hali hazırda bölme komutları içermediğinden birde işaretsiz tam sayılar üzerinde bölme işlemi yapan bir alt program yazmak durumunda kaldım. Böylelikle okumuş olduğum sayısal değeri basamaklarına ayırdım. Sonrasında basamak değerlerini ASCII karaktere çevirmek için sadece her basamağı 0x30 değeri ile toplamak yeterli. Sonuç olarak elimde uart üzerinden gödnerilmeye hazır 4 basamaklı ADC çevrim değeri hazır hale geldi. Bu arada kodları geliştirirken önceki uygulama kodlarını kullandığım için uart kesme kısmını silmedim. Program aynı zamanda uarttan aldığı verileri geri gönderir.(Echo)

Uygulama kodları aşağıdaki gibidir.

;****************************************************************************
;	Uygulama 		: ADC kullanımı		  									*
;	Yazan			: Erhan YILMAZ				  						  	*
;	E-posta			: erhanyilmaz.ytu@gmail.com								*
;	Tarih			: 28-06-2016				  							*
;	Sürüm			: 1.0					  								*
;	Açıklama		: Cortex M0 işlemcisine sahip STM32F051R8 denetleyicisi	*
; 	için assembly dilinde yazılmış ADC kullanım uygulamasıdır. 				*
; 	Geliştirme kartı olarak STM32F0 Discovery kullanılmıştır.				*
;****************************************************************************
 
Stack_Size      EQU     0x00000400			;Stack boyutu tanımlanıyor.(1kb)
 
; Genel amaçlı bit değerleri için tanımlamalar yapılıyor.
BIT0	EQU	0x00000001
BIT1	EQU	0x00000002
BIT2	EQU	0x00000004
BIT3	EQU	0x00000008
BIT4	EQU	0x00000010
BIT5	EQU	0x00000020
BIT6	EQU	0x00000040
BIT7	EQU	0x00000080
BIT8	EQU	0x00000100
BIT9	EQU	0x00000200
BIT10	EQU	0x00000400
BIT11	EQU	0x00000800
BIT12	EQU	0x00001000
BIT13	EQU	0x00002000
BIT14	EQU	0x00004000
BIT15	EQU	0x00008000
BIT16	EQU	0x00010000
BIT17	EQU	0x00020000
BIT18	EQU	0x00040000
BIT19	EQU	0x00080000
BIT20	EQU	0x00100000
BIT21	EQU	0x00200000
BIT22	EQU	0x00400000
BIT23	EQU	0x00800000
BIT24	EQU	0x01000000
BIT25	EQU	0x02000000
BIT26	EQU	0x04000000
BIT27	EQU	0x08000000
BIT28	EQU	0x10000000
BIT29	EQU	0x20000000
BIT30	EQU	0x40000000
BIT31	EQU	0x80000000
 
 
; Kullanılan kaydedicilerin adresleri tanımlanıyor.
 
; NVIC kaydedici adresleri
ISER 	EQU	0xE000E100
ICER 	EQU	0XE000E180
ISPR	EQU	0XE000E200
ICPR	EQU	0XE000E280
IPR0	EQU	0xE000E400
IPR1	EQU	0xE000E404
IPR2	EQU	0xE000E408
IPR3	EQU	0xE000E40C
IPR4	EQU	0xE000E410
IPR5	EQU	0xE000E414
IPR6	EQU	0xE000E418
IPR7	EQU	0xE000E41C
 
; RCC birimi kaydedici adresleri
RCC_BASE		EQU		0x40021000
RCC_CR			EQU		RCC_BASE + 0x00
RCC_CFGR		EQU		RCC_BASE + 0x04
RCC_CIR			EQU		RCC_BASE + 0x08
RCC_APB2RSTR	EQU		RCC_BASE + 0x0C
RCC_APB1RSTR	EQU		RCC_BASE + 0x10
RCC_AHBENR		EQU		RCC_BASE + 0x14
RCC_APB2ENR		EQU		RCC_BASE + 0x18
RCC_APB1ENR		EQU		RCC_BASE + 0x1C
RCC_BDCR		EQU		RCC_BASE + 0x20
RCC_CSR			EQU		RCC_BASE + 0x24
RCC_AHBRSTR		EQU		RCC_BASE + 0x28
RCC_CFGR2		EQU		RCC_BASE + 0x2C
RCC_CFGR3		EQU		RCC_BASE + 0x30
RCC_CR2			EQU		RCC_BASE + 0x34
 
; GPIOA birimi kaydedici adresleri
GPIOA_BASE		EQU		0x48000000
GPIOA_MODER		EQU		GPIOA_BASE + 0x0
GPIOA_OTYPER	EQU		GPIOA_BASE + 0x4
GPIOA_OSPEEDR	EQU		GPIOA_BASE + 0x8
GPIOA_PUPDR		EQU		GPIOA_BASE + 0xc
GPIOA_IDR		EQU		GPIOA_BASE + 0x10
GPIOA_ODR		EQU		GPIOA_BASE + 0x14
GPIOA_BSRR		EQU		GPIOA_BASE + 0x18
GPIOA_LCKR		EQU		GPIOA_BASE + 0x1C
GPIOA_AFRL		EQU		GPIOA_BASE + 0x20
GPIOA_AFRH		EQU		GPIOA_BASE + 0x24
GPIOA_BRR		EQU		GPIOA_BASE + 0x28
 
; GPIOC birimi kaydedici adresleri
GPIOC_BASE		EQU		0x48000800
GPIOC_MODER		EQU		GPIOC_BASE + 0x0
GPIOC_OTYPER	EQU		GPIOC_BASE + 0x4
GPIOC_OSPEEDR	EQU		GPIOC_BASE + 0x8
GPIOC_PUPDR		EQU		GPIOC_BASE + 0xc
GPIOC_IDR		EQU		GPIOC_BASE + 0x10
GPIOC_ODR		EQU		GPIOC_BASE + 0x14
GPIOC_BSRR		EQU		GPIOC_BASE + 0x18
GPIOC_LCKR		EQU		GPIOC_BASE + 0x1C
GPIOC_AFRL		EQU		GPIOC_BASE + 0x20
GPIOC_AFRH		EQU		GPIOC_BASE + 0x24
GPIOC_BRR		EQU		GPIOC_BASE + 0x28
 
; USART1 birimi kaydedici adresleri
USART1_BASE		EQU		0x40013800
USART1_CR1		EQU		USART1_BASE + 0x00
USART1_CR2		EQU		USART1_BASE + 0x04
USART1_CR3		EQU		USART1_BASE + 0x08
USART1_BRR		EQU		USART1_BASE + 0x0C
USART1_GTPR		EQU		USART1_BASE + 0x10
USART1_RTOR		EQU		USART1_BASE + 0x14
USART1_RQR		EQU		USART1_BASE + 0x18
USART1_ISR		EQU		USART1_BASE + 0x1C
USART1_ICR		EQU		USART1_BASE + 0x20
USART1_RDR		EQU		USART1_BASE + 0x24
USART1_TDR		EQU		USART1_BASE + 0x28
 
; ADC birimi kaydedici adresleri
ADC_BASE		EQU		0x40012400
ADC_ISR			EQU		ADC_BASE + 0x00
ADC_IER			EQU		ADC_BASE + 0x04
ADC_CR			EQU		ADC_BASE + 0x08
ADC_CFGR1		EQU		ADC_BASE + 0x0C
ADC_CFGR2		EQU		ADC_BASE + 0x10
ADC_SMPR		EQU		ADC_BASE + 0x14
ADC_TR			EQU		ADC_BASE + 0x20
ADC_CHSELR		EQU		ADC_BASE + 0x28
ADC_DR			EQU		ADC_BASE + 0x40
ADC_CCR			EQU		ADC_BASE + 0x308
 
; Stack için yer ayrılıyor.
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   0x00001000
__initial_sp
 
                PRESERVE8	; Linker bildirimi
                THUMB		; Thumb komut seti kullanılıyor.
 
; Vector Table Mapped to Address 0 at Reset
; Vektör tablosu tanımlanıyor.
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors					   ; Linker bildirimi
; İşlemci tarafından kullanılan kesmeler(exceptions) handler'lar ve stack top adresi tanımlanıyor.
__Vectors       DCD     __initial_sp                   ; Top of Stack
                DCD     Reset_Handler                  ; Reset Handler
                DCD     NMI_Handler                    ; NMI Handler
                DCD     HardFault_Handler              ; Hard Fault Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     SVC_Handler                    ; SVCall Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     PendSV_Handler                 ; PendSV Handler
                DCD     SysTick_Handler                ; SysTick Handler
; External Interrupts
; Denetleyici tarfından kullanılan kesmeler(exceptions) için handler'lar tanımlanıyor.
                DCD     WWDG_IRQHandler                ; Window Watchdog
                DCD     PVD_IRQHandler                 ; PVD through EXTI Line detect
                DCD     RTC_IRQHandler                 ; RTC through EXTI Line
                DCD     FLASH_IRQHandler               ; FLASH
                DCD     RCC_IRQHandler                 ; RCC
                DCD     EXTI0_1_IRQHandler             ; EXTI Line 0 and 1
                DCD     EXTI2_3_IRQHandler             ; EXTI Line 2 and 3
                DCD     EXTI4_15_IRQHandler            ; EXTI Line 4 to 15
                DCD     TS_IRQHandler                  ; TS
                DCD     DMA1_Channel1_IRQHandler       ; DMA1 Channel 1
                DCD     DMA1_Channel2_3_IRQHandler     ; DMA1 Channel 2 and Channel 3
                DCD     DMA1_Channel4_5_IRQHandler     ; DMA1 Channel 4 and Channel 5
                DCD     ADC1_COMP_IRQHandler           ; ADC1, COMP1 and COMP2 
                DCD     TIM1_BRK_UP_TRG_COM_IRQHandler ; TIM1 Break, Update, Trigger and Commutation
                DCD     TIM1_CC_IRQHandler             ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler                ; TIM2
                DCD     TIM3_IRQHandler                ; TIM3
                DCD     TIM6_DAC_IRQHandler            ; TIM6 and DAC
                DCD     0                              ; Reserved
                DCD     TIM14_IRQHandler               ; TIM14
                DCD     TIM15_IRQHandler               ; TIM15
                DCD     TIM16_IRQHandler               ; TIM16
                DCD     TIM17_IRQHandler               ; TIM17
                DCD     I2C1_IRQHandler                ; I2C1
                DCD     I2C2_IRQHandler                ; I2C2
                DCD     SPI1_IRQHandler                ; SPI1
                DCD     SPI2_IRQHandler                ; SPI2
                DCD     USART1_IRQHandler              ; USART1
                DCD     USART2_IRQHandler              ; USART2
                DCD     0                              ; Reserved
                DCD     CEC_IRQHandler                 ; CEC
                DCD     0                              ; Reserved
 
 
                AREA     MAIN, CODE, READONLY
 
; Reset handler routine
; Reset sonrası başlangıç adresi
Reset_Handler    
                EXPORT  Reset_Handler                 [WEAK]	; Linker bildirimi			
 
; GPIOA, GPIOC saatleri aktif
				LDR R0, =RCC_AHBENR		; RCC_AHBENR değerini R0'a yükle
				LDR R1, [R0]			; RCC_AHBENR değişken içeriğini R1'e yükle
				LDR R2, =BIT19+BIT17	; BIT19+BIT17 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; Güncellenmiş RCC_AHBENR değişken içeriğini geri yaz				
 
; USART1 ve ADC clock aktif
				LDR R0, =RCC_APB2ENR	; RCC_APB2ENR değerini R0'a yükle	
				LDR R1, [R0]			; RCC_APB2ENR değişken içeriğini R1'e yükle
				LDR R2, =BIT9+BIT14		; BIT9+BIT14 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; RCC_APB2ENR harici değişkenine BIT9+BIT14 değerini yükle		
 
; GPIOC.8, GPIOC.9 çıkış
				LDR R0, =GPIOC_MODER	; GPIOC_MODER değerini R0'a yükle
				LDR R1, [R0]			; GPIOC_MODER değişken içeriğini R1'e yükle
				LDR R2, =BIT16+BIT18	; BIT16+BIT18 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; GPIOC_MODER harici değişkenine BIT16+BIT18 değerini yükle
 
; GPIOA.0 analog GPIOA.9, GPIOA.10 alternatif fonksiyon
				LDR R0, =GPIOA_MODER	; GPIOA_MODER değerini R0'a yükle
				LDR R1, [R0]			; GPIOA_MODER değişken içeriğini R1'e yükle
				LDR R2, =BIT0+BIT1+BIT19+BIT21	; BIT0+BIT1+BIT19+BIT21 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; Güncellenmiş GPIOA_MODER değişken içeriğini geri yaz
 
; GPIOA.9, GPIOA.10 alternatif fonksiyon 1
				LDR R0, =GPIOA_AFRH		; GPIOA_AFRH değerini R0'a yükle
				LDR R1, [R0]			; GPIOA_AFRH değişken içeriğini R1'e yükle
				LDR R2, =BIT4+BIT8		; BIT4+BIT8 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; GPIOA_AFRH harici değişkenine BIT4+BIT8 değerini yükle
 
; USART1 saat kaynağı HSI(Dahili osilatör)
				LDR R0, =RCC_CFGR3		; RCC_CFGR3 değerini R0'a yükle
				LDR R1, [R0]			; RCC_CFGR3 değişken içeriğini R1'e yükle
				LDR R2, =BIT0+BIT1		; BIT0+BIT1 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; RCC_CFGR3 harici değişkenine BIT0+BIT1 değerini yükle
 
; USART1 baud=9600, HSI=FCK=8MHz,oversampling 16
				LDR R0, =USART1_BRR		; USART1_BRR değerini R0'a yükle
				LDR R1, =0x341			; 0x341 değerini R1'e yükle
				STR R1, [R0]			; USART1_BRR harici değişkenine 0x341 değerini yükle
 
; USART1 uart açık, alma açık, gönderme açık, alma kesmesi açık
				LDR R0, =USART1_CR1		; USART1_CR1 değerini R0'a yükle
				LDR R1, [R0]			; USART1_CR1 değişken içeriğini R1'e yükle
				LDR R2, =BIT0+BIT2+BIT3+BIT5	; BIT0+BIT2+BIT3+BIT5 değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; USART1_CR1 harici değişkenine BIT0+BIT2+BIT3+BIT5 değerini yükle
 
; USART1 (NVIC_EnableIRQ) biriminin kesme oluşturmasına izin ver				
				LDR	R0, =ISER			; ISER değerini R0'a yükle
				LDR R1, [R0]			; ISER değişken içeriğini R1'e yükle
				LDR	R2,	=BIT27			; BIT27 (USART1_IRQn) değerini R2'ye yükle
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR R1, [R0]			; ISER harici değişkenine BIT27 (USART1_IRQn) değerini yükle				
 
; ADC kalibrasyon
				LDR  R0, =ADC_CR	; ADC_CR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_CR registerini R1'e kopyala
				MOVS R0, #BIT0		; R0'a BIT1 değerini yükle (R0=BIT0=ADEN)
				TST  R0, R1			; R0 & R1 (Bit0 test ediliyor)
				BEQ	 ADC_CALIBRATE	; Sonuç 1 değilse ADC_CALIBRATE'e git
				LDR	 R0, =ADC_CR	; ADC_CR değerini R0'a yükle
				MOVS R1, #0			; 0 değerini R1'e yükle
				STR R1, [R0]		; ADC_CR harici değişkenine 0 değerini yükle
ADC_CALIBRATE
				LDR R0, =ADC_CR		; ADC_CR değerini R0'a yükle
				LDR R1, [R0]		; ADC_CR değişken içeriğini R1'e yükle
				LDR R2, =BIT31		; BIT31 değerini R2'ye yükle
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR R1, [R0]		; ADC_CR harici değişkenine BIT31 değerini yükle(R0=BIT31=ADCAL)
ADC_CAL_WAIT
				LDR  R0, =ADC_CR	; ADC_CR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_CR registerini R1'e kopyala
				LDR  R0, =BIT31		; R0'a BIT31 değerini yükle (R0=BIT31=ADCAL)
				TST  R0, R1			; R0 & R1 (Bit1 test ediliyor)
				BNE	 ADC_CAL_WAIT	; Sonuç 0 değilse ADC_CAL_WAIT'e git
 
; ADC çalıştır(Enable)				
				LDR  R0, =ADC_CR	; ADC_CR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_CR değişken içeriğini R1'e yükle
				MOVS R2, #BIT0		; BIT0 değerini R1'e yükle
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR  R1, [R0]		; Güncellenmiş ADC_CR değişken içeriğini geri yaz
ADC_EN_WAIT
				LDR  R0, =ADC_ISR	; ADC_ISR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_ISR registerini R1'e kopyala
				LDR  R0, =BIT0		; R0'a BIT0 değerini yükle (R0=BIT0=ADRDY)
				TST  R0, R1			; R0 & R1 (Bit0 test ediliyor)
				BEQ	 ADC_EN_WAIT	; Sonuç 1 değilse ADC_EN_WAIT'e git
 
; HSI14 RC osilatörünü çalıştır(ADC için varsayılan saat kaynağı)
				LDR  R0, =RCC_CR2	; RCC_CR2 değerini R0'a yükle
				LDR  R1, [R0]		; RCC_CR2 değişken içeriğini R1'e yükle
				MOVS R2, #BIT0		; BIT0 değerini R1'e yükle (R2=BIT0=HSI14ON)
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR  R1, [R0]		; Güncellenmiş RCC_CR2 değişken içeriğini geri yaz
 
; HSI14 Osilatörü hazır olana kadar bekle
HSI14_WAIT
				LDR  R0, =RCC_CR2	; RCC_CR2 değerini R0'a yükle
				LDR  R1, [R0]		; RCC_CR2 registerini R1'e kopyala
				MOVS R0, #BIT1		; R0'a BIT1 değerini yükle (R0=BIT1=HSI14RDY)
				TST  R0, R1			; R0 & R1 (Bit1 test ediliyor)
				BEQ	 HSI14_WAIT		; Sonuç 1 değilse HSI14_WAIT'e git
 
; Başlangıç mesajını gönder	"ERHAN YILMAZ ADC TEST\n\r"
				MOVS R4, #'E'
				BL	USART_VERI_GONDER
				MOVS R4, #'R'
				BL	USART_VERI_GONDER
				MOVS R4, #'H'
				BL	USART_VERI_GONDER
				MOVS R4, #'A'
				BL	USART_VERI_GONDER
				MOVS R4, #'N'
				BL	USART_VERI_GONDER
				MOVS R4, #' '
				BL	USART_VERI_GONDER
				MOVS R4, #'Y'
				BL	USART_VERI_GONDER
				MOVS R4, #'I'
				BL	USART_VERI_GONDER
				MOVS R4, #'L'
				BL	USART_VERI_GONDER
				MOVS R4, #'M'
				BL	USART_VERI_GONDER
				MOVS R4, #'A'
				BL	USART_VERI_GONDER
				MOVS R4, #'Z'
				BL	USART_VERI_GONDER
				MOVS R4, #' '
				BL	USART_VERI_GONDER
				MOVS R4, #'A'
				BL	USART_VERI_GONDER
				MOVS R4, #'D'
				BL	USART_VERI_GONDER
				MOVS R4, #'C'
				BL	USART_VERI_GONDER
				MOVS R4, #' '
				BL	USART_VERI_GONDER
				MOVS R4, #'T'
				BL	USART_VERI_GONDER
				MOVS R4, #'E'
				BL	USART_VERI_GONDER
				MOVS R4, #'S'
				BL	USART_VERI_GONDER
				MOVS R4, #'T'
				BL	USART_VERI_GONDER
				MOVS R4, #'\n'
				BL	USART_VERI_GONDER
				MOVS R4, #'\r'
				BL	USART_VERI_GONDER
 
; Başlangıç animasyonu				
; GPIOC.8, GPIOC.9 çıkışlarını set et				
				LDR R0, =GPIOC_BSRR	; GPIOC_BSRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BSRR registerini R1'e kopyala
				LDR R2, =BIT8+BIT9	; BIT8+BIT9 değerini R2'ye yükle
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BSRR değişken içeriğini geri yaz
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00050000	; 0x00050000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır
 
; GPIOC.8, GPIOC.9 çıkışlarını sıfırla
				LDR R0, =GPIOC_BRR	; GPIOC_BRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BRR registerini R1'e kopyala
				LDR R2, =~(BIT8+BIT9)	; ~(BIT8+BIT9) değerini R2'ye yükle
				ANDS R1, R1, R2		; R1 = R1 AND R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BRR değişken içeriğini geri yaz
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00050000	; 0x00050000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır	
 
; GPIOC.8, GPIOC.9 çıkışlarını set et				
				LDR R0, =GPIOC_BSRR	; GPIOC_BSRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BSRR registerini R1'e kopyala
				LDR R2, =BIT8+BIT9	; BIT8+BIT9 değerini R2'ye yükle
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BSRR değişken içeriğini geri yaz
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00050000	; 0x00050000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır
 
; GPIOC.8, GPIOC.9 çıkışlarını sıfırla
				LDR R0, =GPIOC_BRR	; GPIOC_BRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BRR registerini R1'e kopyala
				LDR R2, =~(BIT8+BIT9)	; ~(BIT8+BIT9) değerini R2'ye yükle
				ANDS R1, R1, R2		; R1 = R1 AND R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BRR değişken içeriğini geri yaz
 
; AD çevrimi için kanal 0'ı seç				
				LDR  R0, =ADC_CHSELR	; ADC_CHSELR değerini R0'a yükle
				LDR  R1, [R0]			; ADC_CHSELR değişken içeriğini R1'e yükle
				MOVS R2, #BIT0			; BIT0 değerini R2'ye yükle (R2=BIT0=CHSEL0)
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR  R1, [R0]			; Güncellenmiş ADC_CHSELR değişken içeriğini geri yaz
LOOP
; AD çevrimi başlat				
				LDR  R0, =ADC_CR		; ADC_CR değerini R0'a yükle
				LDR  R1, [R0]			; ADC_CR değişken içeriğini R1'e yükle
				MOVS R2, #BIT2			; BIT0 değerini R2'ye yükle (R2=BIT2=ADSTART)
				ORRS R1, R1, R2			; R1 = R1 OR R2
				STR  R1, [R0]			; Güncellenmiş ADC_CR değişken içeriğini geri yaz
 
; Çevrim bitene kadar bekle
AD_CONV_WAIT
				LDR  R0, =ADC_ISR	; ADC_ISR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_ISR registerini R1'e kopyala
				MOVS R0, #BIT2		; R0'a BIT6 değerini yükle (R0=BIT2=EOC)
				TST  R0, R1			; R0 & R1 (Bit2 test ediliyor)
				BEQ	 AD_CONV_WAIT	; Sonuç 1 değilse AD_CONV_WAIT'e git
 
;Çevrim sonucunu oku
				LDR  R0, =ADC_DR	; ADC_DR değerini R0'a yükle
				LDR  R1, [R0]		; ADC_DR registerini R1'e kopyala
 
				MOVS R4, #'A'
				BL	USART_VERI_GONDER
				MOVS R4, #'D'
				BL	USART_VERI_GONDER
				MOVS R4, #'C'
				BL	USART_VERI_GONDER
				MOVS R4, #' '
				BL	USART_VERI_GONDER
				MOVS R4, #'V'
				BL	USART_VERI_GONDER
				MOVS R4, #'A'
				BL	USART_VERI_GONDER
				MOVS R4, #'L'
				BL	USART_VERI_GONDER
				MOVS R4, #'U'
				BL	USART_VERI_GONDER
				MOVS R4, #'E'
				BL	USART_VERI_GONDER
				MOVS R4, #'='
				BL	USART_VERI_GONDER
				MOV	 R4, R1
				BL	DECIMAL_TO_BCD		; AD çevrim sonucunu BCD'ye çevir
				ADDS R3, #0x30			; Binler basamak değerini ASCII karaktere çevir
				MOV	 R4, R3				; R3 içerğini R4'e kopyala
				BL	USART_VERI_GONDER	; Yüzler basmağını uart üzerinden gönder
				ADDS R2, #0x30			; Yüzler basamak değerini ASCII karaktere çevir
				MOV	 R4, R2				; R2 içerğini R4'e kopyala
				BL	USART_VERI_GONDER	; Yüzler basmağını uart üzerinden gönder
				ADDS R1, #0x30			; Onlar basamak değerini ASCII karaktere çevir
				MOV	 R4, R1				; R1 içerğini R4'e kopyala
				BL	USART_VERI_GONDER	; Onlar basmağını uart üzerinden gönder
				ADDS R0, #0x30			; Birler basamak değerini ASCII karaktere çevir
				MOV	 R4, R0				; R0 içerğini R4'e kopyala
				BL	USART_VERI_GONDER	; Birler basmağını uart üzerinden gönder
 
				MOVS R4, #'\n'
				BL	USART_VERI_GONDER
				MOVS R4, #'\r'
				BL	USART_VERI_GONDER
 
; AD çevrim bitti animasyonu				
; GPIOC.8, GPIOC.9 çıkışlarını set et				
				LDR R0, =GPIOC_BSRR	; GPIOC_BSRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BSRR registerini R1'e kopyala
				LDR R2, =BIT8+BIT9	; BIT8+BIT9 değerini R2'ye yükle
				ORRS R1, R1, R2		; R1 = R1 OR R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BSRR değişken içeriğini geri yaz
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00050000	; 0x00050000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır
 
; GPIOC.8, GPIOC.9 çıkışlarını sıfırla
				LDR R0, =GPIOC_BRR	; GPIOC_BRR değerini R0'a yükle
				LDR R1, [R0]		; GPIOC_BRR registerini R1'e kopyala
				LDR R2, =~(BIT8+BIT9)	; ~(BIT8+BIT9) değerini R2'ye yükle
				ANDS R1, R1, R2		; R1 = R1 AND R2
				STR  R1, [R0]		; Güncellenmiş GPIOC_BRR değişken içeriğini geri yaz
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00050000	; 0x00050000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır
 
; Bir süre(R4 değişkeni içeriği kadar) bekle
				LDR R4, =0x00500000	; 0x00500000 değerini R4'e yükle
				BL		bekle		; Gecikme(bekle) alt programını çağır
 
				B 	LOOP			; Ana döngü başına(LOOP) git	
				WFI					; Kesme için bekle(enerji tasarruf modu)
				B .					; Debug yaparken WFI komutu çalışmadığı için sonsuz döngüye gir
; Ana program sonu
 
; İşaretsiz sayılar için bölme alt programı.
; Çıkarma temeline dayanarak çalıştığından
; icra süresi sayılar(Bölen, Bölünen) arasında ki farka göre değişmektedir.
DIV_UINT
				; Inputs
				; R0 = dividend	(Bölünen)
				; R1 = divider	(Bölen)
				; Outputs
				; R0 = quotient (Bölüm)
				; R1 = remainder (Kalan)
				PUSH {R2}		; Ana programda kullanılan değişkenleri stack'e it
				MOVS  R2, #0	; Geçici bölüm değişkeni		
DIV_LOOP		CMP	  R0, R1	; Bölen ile bölüneni karşılaştır
				BCC	  DIV_END	; Bölünen bölenden küçük ise programı sonlandır
				SUBS  R0, R1	; Değilse Böleni Bölünenden çıkar
				ADDS  R2, #1	; Bölüm değişkenini arttır
				B	  DIV_LOOP	; Bölmeye devam et
DIV_END			MOV   R1, R0	; Kalanı R1'e yükle
				MOV	  R0, R2	; Bölümü R0'e yükle
				POP {R2}		; Ana programda kullanılan değişkenleri stack'tan çek
				BX	LR			; Alt programdan geri dön
 
; 4 basamağa kadar olan işaretsiz sayıları BCD'ye çeviren alt program
DECIMAL_TO_BCD	
				; Giriş
				; R4 Azami 4 basamaklı iaretsiz tam sayı
				; Çıkışlar
				; R0 Birler basamağı
				; R1 onlar basamağı
				; R2 yüzler basamağı
				; R3 binler basamağı
				PUSH {LR}		; LR değişkenini stack'e it
				MOV	 R0, R4		; R4 değerini R0'a(Bölünen) kopyala
				LDR	 R1, =1000	; R1=1000(Bölen)
				BL	 DIV_UINT	; Bölme işlemini yap
				MOV  R3, R0		; Bölümü(Binler basamağı) R3'e kopyala
				MOV  R0, R1		; Kalanı R0'a kopyala
				MOVS R1, #100	; R1=100(Bölen)
				BL	 DIV_UINT	; Bölme işlemini yap
				MOV  R2, R0		; Bölümü(Yüzler basamağı) R2'ye kopyala
				MOV	 R0, R1		; Kalanı R0'a kopyala
				MOVS  R1, #10	; R=10(Bölen)
				BL	 DIV_UINT	; Bölme işlemini yap
				MOV	 R4, R1		; Kalanı(Birler basamağı)R4'e kopyala
				MOV	 R1, R0		; Bölümü R1'e(Onlar basamağı) kopyala
				MOV  R0, R4		; Birler basamağını R0'a kopyala
				POP  {R4}		; Stackta olan LR değerini R4'e çek
				BX	 R4			; Alt programdan geri dön
 
; Gecikme alt programı
bekle
				SUBS R4, #1			; R4=R4-1
				BNE bekle			; Sonuç 0 değilse label'e git
				BX	LR				; Alt programdan geri dön
 
; USART1 veri gönderme alt programı
USART_VERI_GONDER
				PUSH {R0,R1}		; Ana programda kullanılan değişkenleri stack'e it
 
; Gitmekte olan veri var mı diye kontrol et				
TX_WAIT
				LDR  R0, =USART1_ISR; USART1_ISR değerini R0'a yükle
				LDR  R1, [R0]		; USART1_ISR registerini R1'e kopyala
				MOVS R0, #BIT6		; R0'a BIT6 değerini yükle (R0=BIT6=TC)
				TST  R0, R1			; R0 & R1 (Bit6 test ediliyor)
				BEQ	 TX_WAIT		; Sonuç 1 değilse TX_WAIT'e git
 
; Gitmekte olan veri yoksa alınan veriyi gönder
				LDR R0, =USART1_TDR	; USART1_TDR değerini R0'a yükle
				STR R4, [R0]		; USART1_TDR harici değişkenine(gönderme değişkeni) R4 değişken değerini yükle
 
				POP {R0,R1}			; Ana programda kullanılan değişkenleri stack'tan çek
				BX	LR				; Alt programdan geri dön
 
; Dummy Exception Handlers (infinite loops which can be modified)
; Kesme(exceptions) vektörleri için tanımlanmış iç boş sonsuz döngüye giren handler'lar
NMI_Handler     
                B       .       
HardFault_Handler
                B       .
SVC_Handler     
                B       .
PendSV_Handler  
                B       .
SysTick_Handler 
                B       .
WWDG_IRQHandler
PVD_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_1_IRQHandler
EXTI2_3_IRQHandler
EXTI4_15_IRQHandler
TS_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_3_IRQHandler
DMA1_Channel4_5_IRQHandler
ADC1_COMP_IRQHandler 
TIM1_BRK_UP_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM6_DAC_IRQHandler
TIM14_IRQHandler
TIM15_IRQHandler
TIM16_IRQHandler
TIM17_IRQHandler
I2C1_IRQHandler
I2C2_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
 
; USART1 kesme programı
USART1_IRQHandler
; Ana programda kullanılan değişkenleri ve LR değişkenini stack'a it
				PUSH {R0,R1,R2,R4,LR}	
 
; Gelen veri var mı diye kontrol et					
				LDR  R0, =USART1_ISR	; USART1_ISR değerini R0'a yükle
				LDR  R1, [R0]		 	; USART1_ISR registerini R1'e kopyala
				MOVS R0, #BIT5		    ; R0'a BIT5 değerini yükle(R0=BIT5=RXNE)
				TST  R0, R1				; R0 & R1 (Bit5 test ediliyor)
				BEQ	 USART1_KESME_SONU	; Sonuç 1 değilse USART1_KESME_SONU'na git
 
; Veri geldiyse oku
				LDR  R0, =USART1_RDR; USART1_RDR(gelen veri) değerini R0'a yükle
				LDR  R4, [R0]		; USART1_RDR registerini R4'e kopyala
				BL	 USART_VERI_GONDER		; USART_VERI_GONDER alt programını çağır
 
USART1_KESME_SONU
; Ana programda kullanılan değişkenleri ve geri dönüş değerini stack'tan çek
				POP	{R0,R1,R2,R4,PC} 
USART2_IRQHandler
CEC_IRQHandler   
                B .
	ALIGN	; Adres hizalama Assembler bildirimi
	END		; Program sonu assmbler bildirimi

Uygulamalar geliştikçe uygulama kodlarıda artmaya başladı. Bu uygulama yaklaşık 650 satırdan oluşmakta. Uygulamanın çalışması basit. Denetleyicimiz ilk çalışır çalışmaz, başlangıç, kesme vs. gibi ayarları yaparak namımı yürüten açılış mesajını uart üzerinden göndererek ana döngüye girer, normal çalışmasına devam eder.

Ana döngüde yapılan iş basit. ADC çevrimi yapılır sonuç basamaklarına(BCD) ayırılarak ascii karaktere çevirilir, münasip bir şekilde uart üzerinden gönderilir. Sonrasında çevrim işleminin yapıldığını göstermek için küçük bir led blink yapılır. Daha sonra bir süre beklemeden sonra tekrar aynı işlemler tekrarlanır.

Ayrıca bu program ile beraber iki alt programı içi içe çağırmam gerekti. Bunun için Cortex-M0 işlemcisi iç içe alt program çağırmada geri dönüş adreslerini otomatik olarak kayıt etmediği için (yani sadece en son çağırılan alt programın dönüş adresini kayıt ediyor. Daha sonra alt program içinde başka bir alt program çağırılırsa dönüş değeri üstüne yazılıyor.) bunu kod içerisinde manuel yapmak gerekiyor. Yani stack’e kendiniz itmeniz gerekiyor. Aynı zamanda önceki kodlarımda bitlerin değerini değiştirirken AND/OR(Bit manuplasyon) işlemleri kullanmıyordum. Hatta bu yüzden önceki yazımda bu yüzden debug ile ilgili bir sorun yaşamaştım. Artık o alışkanlığı bırakıp bütün bit manüplasyon işlemlerinde AND/OR işlemlerini kullanmaya başladım. Kodumuz bir kaç satır büyük olabilir ama daha güvenli ve az saç baş yolduran cinsten olur.

AD çevrimi için tek kanal(GPIOA.0/CH0) kullandım. Analog giriş değerini kullanmak için evde bulduğum bir potansiyometreyi bağladım. Böylelikle 0-4095 arasında olan AD çevrim sonuçlarını gözlemledim. Uygulamanın ekran çıktısı aşağıdaki gibidir.

Şekil-1

Şekil-1’de uygulamanın çıktı değerleri görülmektedir. Görüldüğü gibi uygulamamız açılış mesajının ardından kanal0 üzerinden okuduğu ADC değerlerini uart üzerinden göndermektedir. Gönderme esnasında bende potansiyometre ile oynarak çevrim sonuçlarının değişmesini sağladım. Bu şekilde temel bir ADC uygulamasını gerçekleştirmiş olduk. Uygulamaya ait çalışma görüntüsü şekil-2’de ki gibidir.

Şekil-2

Görüldüğü gibi uygulamada bir kaç jumper kablo, Discovery kit, USB-Uart dönüştürücü, USB kablo ve potansiyometre kullanılmıştır. Potansiyometreini iki dış ucundan biri kart üzerindeki VDD, diğeri ise GND pinine bağlanmıştır. Doğal olarak orta pini ise ADC kanal0(GPIOA.0) girişine bağlanmıştır.

Böylelikle bir yazının daha sonuna gelmiş bulunuyoruz elhamdülillah. Uygulama ait dosyalara vs. buradan ulaşabilirsiniz. Gözümden kaçan herhangi bir hata varsa, öneri, görüş vs. yada bildirirseniz sevinirim. Faydalı olması dileğiyle, bir sonraki yazıda görüşmek üzere inşaallah…

Esen kalın.