1. 程式人生 > >Exynos4412裸機開發綜合練習

Exynos4412裸機開發綜合練習

下面是一個案例需求:

1、編寫一段程式,該程式的主要功能是監控電路板上的電壓值,若電壓值超過當前的電壓限制則通過蜂鳴器報警,通過按鍵解除報警;

2、其具體要求如下; 

a) 程式下載20s後,進入電壓採集狀態(使用RTC ALARM功能完成), 要求1s採集1次電路板電壓值;(採用RTC TIME TICK完成)

b) 每次電壓採集完成後,通過COM2將採集到的電壓值傳送到PC,在PC端可通過串列埠除錯助手檢視當前的電壓值;

c) 每次電壓採集完成後,比較當前的電壓值是否正常正常的電壓值為(1V~2V),若當前採集的電壓值異常,則通過蜂鳴器發出報警訊號;

d) 報警訊號的解除通過電路板上的KEY2控制( 通過按下KEY2使蜂鳴器停止鳴叫);

下面是具體實現:

1、標頭檔案定義

0) -- exynos_4412.h

內容過多,這裡不予以展示了,在前面的文章中均可找到相關暫存器定義

1) -- adc.h

#ifndef __ADC_H_
#define __ADC_H_

void adc_init(int temp);
void adc_collect(void);

#endif

2) -- key.h

#ifndef _KEY_H_
#define _KEY_H_

void key2_init(void);

#endif

3) -- pwm.h

#ifndef __PWM_H__
#define __PWM_H__

void pwm_init(void);
void beep_on(void);
void beep_off(void);
#define SYS_SET_FREQUENCE 25000
void beep_set_frequence( unsigned int fre );

#endif

4) -- rtc.h

#ifndef _RTC_H_
#define _RTC_H_

void rtc_init(void);
void rtc_tic(void);
void rtc_alarm(void);

#endif

5) -- uart.h 

#ifndef _UART_H
#define	_UART_H

void putc(const char data);
void puts(const  char  *pstr);
void uart_init(void);

extern void putc(const char data);
extern void puts(const  char  *pstr);
extern void uart_init(void);

#endif

2、具體函式實現:

1) -- adc.c

/*
 * adc.c
 *
 *  Created on: 2016-2-29
 *      Author: Administrator
 */
#include "exynos_4412.h"

//ADC初始化函式
adc_init(int temp)
{
	// 初始化A/D控制暫存器
	// ADCCON [16]位置1,12bit輸出;[14]位置1,允許預分頻; [13:6] = 99,預分頻值為99;
	// [1]位置1,採用讀啟動方式啟動ADC;
	// A/D轉換時間計算: PCLK = 100 MHZ,PRESCALER = 99,則 12 位轉換時間為 100MHz/(99+1) = 1 MHZ
	ADCCON = (1 << 16 | 1 << 14 | 99 <<6 | 1 << 1);
	ADCMUX = 3; //電壓輸入通道選擇,檢視原理圖,ADC連線 XadcAIN3,這裡將ADCMUX = 3;
	temp = ADCDAT & 0xfff; // temp用於存放轉換的資料值,由於是讀啟動方式啟動ADC,第一次讀是讀不到正確值的,
						   // 所以這裡先讀取依次進行初始化。
}

//ADC 採集函式
adc_collect()
{
	unsigned int temp;
	adc_init(temp);

	while(!(ADCCON & (1 << 15))); //讀取ADCCON [15]位,當其為1時,A/D轉換結束
	temp = ADCDAT & 0xfff; // 讀取ADCDAT低12位,獲取電壓值
	temp = 18 * 100 * temp/0xfff; // 電壓轉換公式,電壓最大值為1.8V,temp 範圍為 0 ~ 4096
								  // 由於沒有浮點型標頭檔案,這裡不識別浮點型,這裡將其轉換成mv,
								  // 其實應該是 1.8*1000*temp/0xfff,但1.8不被識別,這裡用18*100 。
	printf("電壓值 = %d mV\n",temp);
	if((temp > 2000)||(temp < 1000)) // 這裡設正常值為 1000mv ~ 2000mV。
	{
		printf("電壓異常!\n");
		beep_on(); //電壓值異常時,蜂鳴器報警
	}
	else
	{
		beep_off(); // 如果調整到正常值,關閉蜂鳴器。
	}
}

2) -- key.c

/*
 * key.c
 *
 *  Created on: 2016-2-29
 *      Author: Administrator
 */

#include "exynos_4412.h"

//按鍵中斷 初始化函式
key2_init()
{
	//1、 外設級暫存器設定
	GPX1.CON =GPX1.CON & (~(0xf << 4)) |(0xf << 4); //配置引腳功能為外部中斷,這裡key2所連引腳為CPX1_1
	GPX1.PUD = GPX1.PUD & (~(0x3 << 2));  //關閉上下拉電阻

	EXT_INT41_CON = EXT_INT41_CON &(~(0xf << 4))|(0x2 << 4); //外部中斷觸發方式
	EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1 << 1));  //使能中斷

	// 2、GIC級暫存器設定
	// 使能分配器
	ICDDCR = 1;
	// 使能相應中斷到分配器,ICDISER每1bit控制一中斷源;
	// EINT[9]中斷號為57,在ICDISER1 第[25]位置1;
	ICDISER.ICDISER1 = ICDISER.ICDISER1 | (0x1 << 25);
	// ICDIPTR每8位表示一中斷源對應的CPU介面,所以一個ICDIPTR控制4箇中斷源
	// 這裡中斷號57在ICDPTR14 第[15:8]設定
	ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xff << 8))|(0x1 << 8); //選擇CPU介面

	//3、CPU0級暫存器設定
	CPU0.ICCPMR = 255; //中斷遮蔽優先順序
	CPU0.ICCICR = 1;   //使能中斷到CPU
}

3) -- pwm.c

#include "exynos_4412.h"
#include "pwm.h"

// 蜂鳴器函式配置,這裡蜂鳴器是無源的,由PWM定時器控制,管腳為GPD0_0
void pwm_init(void)
{
	GPD0.CON = GPD0.CON & (~(0xf))| (0x2 << 0); //GPD0_0 由 GPD0.CON [3:0]控制,置2為TOUT_0
	GPD0.PUD = GPD0.PUD & (~(0xf)) ; //禁用上拉/下拉電阻

	//定時器配置,這裡使用定時器0
	// 1、設定預分頻值,範圍為0~255,這裡設為249
	PWM.TCFG0 = PWM.TCFG0 & (~(0xff))|0xf9;
	// 2、設定分頻器分頻值,有1、1/2、1/4、1/8、1/16 五種因子選擇
	// TCFG1 [3:0]用於配置Time0,這裡置2,選擇分頻值為1/4
	PWM.TCFG1 = PWM.TCFG1 & (~(0xf)) | 0x2; // 分頻後, f = 100MHz/(250)/4 = 100kHz
	//3、TCMPB0 TCNTB0 配合進行佔空比設定,
	// 定時器計數緩衝暫存器(TCNTBn)把計數器初始值下載到遞減計數器中。
	// 定時器比較緩衝暫存器(TCMPBn)把其初始值下載到比較暫存器中,
	// 並將該值與遞減計數器的值進行比較。當遞減計數器和比較暫存器值相同時,輸出電平翻轉。
	// 遞減計數器減至0後,輸出電平再次翻轉,完成一個輸出週期。
	// 這裡將 TCMPB0設定為50,TCNTB0設為100,佔空比為50%。
	PWM.TCMPB0 = 50;
	PWM.TCNTB0 = 100;
	// 4、啟動Time0,且第一次要手動更新,將TCMPB0和TCNTB0的值載入進遞減計數器
	PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 1) ;
}

// 開啟蜂鳴器
void beep_on(void)
{
	PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 3) ; //自動載入TCMPB0和TCNTB0的值
}

//關閉蜂鳴器
void beep_off(void)
{
	PWM.TCON = PWM.TCON & (~(1 << 0)) ; //[0]位置0,關閉定時器0
}

//#define SYS_SET_FREQUENCE 25000
void beep_set_frequence( unsigned int fre )
{
	//若蜂鳴器的發聲頻率為0則返回
	if( 0==fre )
		return ;

	PWM.TCMPB0 =  SYS_SET_FREQUENCE/(fre+fre);   //根據設定頻率重新設定計數器比較的值
	PWM.TCNTB0 =  SYS_SET_FREQUENCE/fre;			//根據頻率重新調整計數值

}

4) -- rtc.c

/*
 * rtc.c
 *
 *  Created on: 2016-2-29
 *      Author: Administrator
 */
#include "exynos_4412.h"

//RTC初始化函式
void rtc_init(void)
{
	RTCCON = 1; // RTC控制使能
	// 通過設定 BCD系列暫存器的值,對年月日時分秒進行配置
	RTC.BCDYEAR = 0x16;
	RTC.BCDMON = 0x2;
	RTC.BCDDAY = 0x29;
	RTC.BCDHOUR = 0x18;
	RTC.BCDMIN = 0x24;
	RTC.BCDSEC = 0x00;
	RTCCON = 0; //RTC控制禁止
}

// 滴答計時器配置
void rtc_tic(void)
{
	// RTCCON [7:4]用於設定滴答計時器子時鐘源選擇,這裡設為 0000,即32768Hz
	// RTCCON [8] 置1,滴答計時器使能
	RTCCON = RTCCON & (~(0xf << 4)) | (1 << 8);
	// 配置TICCNT暫存器,這裡設定為32768,時鐘源為32768Hz, 1s發生一次中斷。
	TICCNT = 32768;

	ICDDCR = 1;  //使能分配器
	ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 13); //使能相應中斷到分配器
	ICDIPTR.ICDIPTR19 = ICDIPTR.ICDIPTR19 & (~(0xff << 8))|(0x1 << 8); //選擇CPU介面
	CPU0.ICCPMR = 255; //中斷遮蔽優先順序
	CPU0.ICCICR = 1;   //使能中斷到CPU
}

// RTC 鬧鐘設定
void rtc_alarm(void)
{
	int i = 20;
	// 配置RTCALM.ALM暫存器,第[6]位置1,鬧鐘使能;第[0]位置1,秒時鐘使能
	RTCALM.ALM = (1 << 6)|(1 << 0);
	RTCALM.SEC = 0x20; // SEC設為20,每到20秒時,鬧鐘到時,發生一次中斷
	printf("請等待20s....\n");
	ICDDCR = 1;  //使能分配器
	ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 12); //使能相應中斷到分配器
	ICDIPTR.ICDIPTR19 = ICDIPTR.ICDIPTR19 & (~(0xff << 0))|(0x1 << 0); //選擇CPU介面
	CPU0.ICCPMR = 255; //中斷遮蔽優先順序
	CPU0.ICCICR = 1;   //使能中斷到CPU
	while(i != 1)
	{
		printf("還剩 %-2d s\r", --i);
		mydelay_ms(1000);
	}
	printf("\n");
}

5) -- uart.c

#include "exynos_4412.h"

// UART初始化函式
void uart_init()
{
	// COM2口 Rx Tx分別連線GPA1_0 GPA1_1
	// GPA1 [3:0]位 置2,設為UART_2_RXD,[7:4]位置2,設為UART_2_TXD;
	GPA1.CON = (GPA1.CON & ~0xFF ) | (0x22); //GPA1_0:RX;GPA1_1:TX

	// 設定傳輸格式:ULCONn暫存器[1:0]用於設定資料位bit數,這裡設為8
	UART2.ULCON2 = 0x3;
	// 設定UART工作模式:UCONn暫存器  [3:2] [1:0] 均置為1 ,Tx Rx 均設為中斷或輪詢模式
	UART2.UCON2 = 0x5;

	/*
	 * 波特率設定
	 	根據給定的波特率、所選擇時鐘源頻率,
		可以通過以下公式計算 UBRDIVn 暫存器 (n 為 0~4,對應 5個 UART 通道 )的值。
		UBRDIVn = (int)( UART clock / ( buad rate x 16) ) – 1
		上式計算出來的 UBRDIVn 暫存器值不一定是整數,
		UBRDIVn 暫存器取其整數部分,小部分由 UFRACVALn 暫存器設定,
		例如,當UART clock為100MHz時,要求波特率為115200 bps,則:
		100000000/(115200 x 16) – 1 = 54.25 – 1 = 53.25
		UBRDIVn = 整數部分 = 53
		UFRACVALn/16 = 小數部分 = 0.25
		UFRACVALn = 4
	 */
	UART2.UBRDIV2 = 0x35;
	UART2.UFRACVAL2 = 0x4;
}

void putc(const char data)
{
	while(!(UART2.UTRSTAT2 & 0X2));
	UART2.UTXH2 = data;
	if (data == '\n')
			putc('\r');
}
char getc(void)
{
	char data;
	while(!(UART2.UTRSTAT2 & 0x1));
	data = UART2.URXH2;
	if ((data == '\n')||(data == '\r'))
		{
			putc('\n');
			putc('\r');
		}else
			putc(data);
	return data;
}
void puts(const  char  *pstr)
{
	while(*pstr != '\0')
		putc(*pstr++);
}
void gets(char *p)
{
	char data;
	while((data = getc())!= '\r')
	{
		if(data == '\b')
		{
			p--;
		}
		*p++ = data;
	}
	if(data == '\r')
	*p++ = '\n';
	*p = '\0';
}


3、main函式

#include "exynos_4412.h"
#include "adc.h"
#include "key.h"
#include "pwm.h"
#include "rtc.h"
#include "uart.h"

void mydelay_ms(int time)
{
	int i, j;
	while(time--)
	{
		for (i = 0; i < 5; i++)
			for (j = 0; j < 514; j++);
	}
}

void do_irq(void)
{
	static int a = 1;
	int irq_num;
	irq_num = CPU0.ICCIAR&0x3ff;  //獲取中斷號
	switch(irq_num)
	{
		case 57:	//按鍵中斷
			beep_off();
			printf("請將電壓調到正常值!!\n");
			mydelay_ms(1000); //延時1s,等待電壓調整
			EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); //清GPIO中斷標誌位
			ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); //清GIC中斷標誌位
		break;

		case 76:	// RTC 鬧鐘中斷
			printf("20s已到,開始採集電壓值:\n");
			rtc_tic(); // 20s 到後,呼叫滴答計時器

			RTCALM.ALM = RTCALM.ALM & (~(1 << 6));//關掉鬧鐘,防止下一個20s中斷再次發生
			RTCINTP	 = RTCINTP | (1 << 1); //清RTC中斷標誌位
			ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 12); //清GIC中斷標誌位
			break;

		case 77:	//滴答計時器中斷
			adc_collect();	//呼叫ad取樣函式
			RTCINTP	 = RTCINTP | (1 << 0);	//清RTC中斷標誌位
			ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 13); //清GIC中斷標誌位
			break;
	}
	CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; //清cpu中斷標誌位
}
/*
 *  裸機程式碼,不同於LINUX 應用層, 一定加迴圈控制
 */
int main (void)
{
	printf("\n");
	printf("------------------practice--------------------\n");

	uart_init();
	pwm_init();
	rtc_init();
	key2_init();

	rtc_alarm();	//呼叫alarm函式,開始定時

	while(1)	//什麼都不做,等待中斷髮生
	{

	}
   return 0;
}


將程式下載到開發板中,執行結果如下:

------------------practice--------------------
請等待20s....
20s已到,開始採集電壓值:

電壓值 = 1219 mV
電壓值 = 1218 mV
電壓值 = 1219 mV
電壓值 = 1219 mV
電壓值 = 1222 mV
電壓值 = 1333 mV
電壓值 = 1391 mV
電壓值 = 1390 mV
電壓值 = 1403 mV
電壓值 = 1496 mV
電壓值 = 1800 mV
電壓值 = 1560 mV
電壓值 = 873 mV
電壓異常!
電壓值 = 825 mV
電壓異常!
電壓值 = 825 mV
電壓異常!
電壓值 = 826 mV
電壓異常!
電壓值 = 826 mV
電壓異常!
請將電壓調到正常值!!
電壓值 = 825 mV
電壓值 = 825 mV
電壓值 = 826 mV
電壓異常!
請將電壓調到正常值!!
電壓值 = 827 mV
電壓異常!
電壓值 = 825 mV
電壓異常!
電壓值 = 825 mV
電壓異常!
電壓值 = 684 mV
電壓異常!
電壓值 = 143 mV
電壓異常!
電壓值 = 364 mV
電壓異常!
電壓值 = 1114 mV
電壓值 = 1121 mV
電壓值 = 1120 mV
電壓值 = 1120 mV
電壓值 = 1121 mV
電壓值 = 1121 mV
電壓值 = 1120 mV
電壓值 = 1121 mV

相關推薦

Exynos4412裸機開發綜合練習

下面是一個案例需求: 1、編寫一段程式,該程式的主要功能是監控電路板上的電壓值,若電壓值超過當前的電壓限制則通過蜂鳴器報警,通過按鍵解除報警; 2、其具體要求如下;  a) 程式下載20s後,進入電壓採集狀態(使用RTC ALARM功能完成), 要求1s採集1次電路板電壓值

Exynos4412裸機開發 —— RTC 實時時鐘單元

      RTC(Real-Time Clock) 實時時鐘。RTC是積體電路,通常稱為時鐘晶片。在一個嵌入式系統中,通常採用RTC來提供可靠的系統時間,包括時分秒和年月日等,而且要求在系統處於關機狀態下它也能正常工作(通常採用後備電池供電)。它的外圍也不需要太多的輔助電

Exynos4412裸機開發——中斷處理

       以KEY2控制LED3亮滅為例: 一、輪詢方式 【0】檢測按鍵k2,按鍵k2按下一次,燈LED2閃一次。 【1】檢視原理圖,連線引腳和控制邏輯 (1)按鍵k2 連線在GPX1_1引腳 (2)控制邏輯        k2 按下  ---- K2閉合 ----

Exynos4412裸機開發 —— 看門狗定時器

一、看門狗定時器概述      看門狗(WatchDog Timer) 定時器和PWM的定時功能目的不一樣。它的特點是,需要不同的接收訊號(一些外接看門狗晶片)或重新設定計數器,保持計數值不為0。一旦一些時間接收不到訊號,或計數值為0,看門狗將發出復位訊號復位系統或產生

Exynos4412裸機開發——PWM定時器

一、PWM定時器 4412時鐘為我們提供了PWM定時器,在4412中共有5個32位的定時器,這些定時器可傳送中斷訊號給ARM子系統。另外,定時器0、1、2、3包含了脈衝寬度調製(PWM),並可驅動其拓展的I/O。PWM對定時器0有可選的dead-zone功能,以支援大電流裝

【Luogu】【關卡1-8】BOSS戰-入門綜合練習2(2017年10月)

c代碼 更新 line logs pen 會有 我們 eof end P1426 小魚會有危險嗎 我個人覺得這個題目出的不好,沒說明白,就先只粘貼的AC代碼吧 1 #include <bits/stdc++.h> 2 using namespace st

vue組件父子間通信之綜合練習--假的聊天室

ner name type 屬性 urn ejs rec 用戶輸入 for <!doctype html> <html> <head> <meta charset="UTF-8"> <title>組件父

Python基礎綜合練習

img OS 綜合 fill .com inf tle rtl 基礎 import turtle def mygoto(x, y): turtle.up() turtle.goto(x, y) turtle.down() def draww

組合數據類型綜合練習

括號 不能 由於 元素 字符串 print 有序 for 總結 1.組合數據類型練習: 分別定義字符串,列表,元組,字典,集合,並進行遍歷。 定義字符串並進行遍歷 >>> str = ‘Micheal‘ >>> for i in str

組合數據類型綜合練習:1.組合數據類型練習

列表 類型 練習 綜合練習 charm 組合 better clas true #字符串 s = ‘Hello‘ for i in s: print(i) # 列表 ls = [‘p‘, ‘y‘, ‘Char‘, ‘m‘] for i in ls:

Unix系統編程()open,read,write和lseek的綜合練習

har ring strtol 開始 splay 進制 void oct unsigned 需求:程序的第一個命令行參數為將要打開的文件名稱,余下的參數則指定了文件上執行的輸入輸出操作。每個表示操作的參數都以一個字母開頭,緊跟以相關值(中間無空格分隔)。 soffet:

綜合練習:英文詞頻統計

ldr one Go 處理 AC 空格 sorted 意義 spl 詞頻統計預處理 下載一首英文的歌詞或文章 將所有,.?!’:等分隔符全部替換為空格 將所有大寫轉換為小寫 生成單詞列表 生成詞頻統計 排序 排除語法型詞匯,代詞、冠詞、連詞 輸出詞頻最大TOP10 s

綜合練習:詞頻統計

side st2 days pre forever oms rev item color song = ‘‘‘ An empty street,An empty house,A hole inside my heart,I‘m all alone,The rooms ar

第1章 綜合練習

Java第1章 綜合練習 1.1 綜合練習一A:鍵盤錄入3個學生信息(學號,姓名,年齡,居住地)存入集合,要求學生信息的學號不能重復B:遍歷集合把每一個學生信息存入文本文件C:每一個學生信息為一行數據,每行學生的學號,姓名,年齡和居住地在文件中均以逗號分隔1.1.1 案例代碼一:[AppleScript] 純

數據庫作業14——綜合練習(二) 反饋情況

tro 物理 加油 char 插入 pad 代碼規範 保存 沒有 數據庫作業14——綜合練習(二) 反饋情況 一、作業要求復述 1、創建數據庫CPXS,保存於E盤根目錄下以自己學號+姓第一個字母(阿拉伯數字+大寫字母)方式創建的文件夾中,初始大小5MB,最大20MB,以10

SQL作業:綜合練習(二)的返評

庫文件 spl val 查找 括號 冰箱 HR 題目 tar 一:作業題目:綜合練習(二) 二:題目要求: 1、創建數據庫CPXS,保存於E盤根目錄下以自己學號+姓第一個字母(阿拉伯數字+大寫字母)方式創建的文件夾中,初始大小5MB,最大20MB,以10%方式增長,日誌文件

0511JS綜合練習

現在 rom while += else div nbsp 遊戲 write 一、一個遊戲,前20關是每一 關自身的分數,21-30關每一關是10分,31-40關,每一關是20分,41-49關,每一關是30分,50關,是100分,輸入你現在闖到的關卡數,求你現在擁有的分數.

掛事件綜合練習

none left 段子 meta length rip XA ;內 text <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <

列表、元組、字典、集合的定義、操作與綜合練習

alt 定義 cor sco end OS bubuko move remove l = [‘Lucy‘,‘Abb‘,‘Lily‘] l.append(‘Abb‘) l.pop() print(1) t = (‘Lucy‘,‘Abb‘,‘Lily‘) scores =