这个程序表现得和预期的一样,但我认为可以做一些更好的事情,因为我是一个新手C程序员。我怀疑中断处理程序可以使用其他方式来调用硬件,而不是直接内存。你能看一下并告诉我什么可以改进吗?
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
/* Include header file for alt_irq_register() */
#include "alt_irq.h"
extern int initfix_int(void);
extern void puttime(int* timeloc);
extern void puthex(int time);
extern void tick(int* timeloc);
extern void delay(int millisec);
extern int hexasc(int invalue);
#define TRUE 1
#define KEYS4 ( (unsigned int *) 0x840 )
#define NULL_POINTER ( (void *) 0)
int timeloc = 0x5957; /* startvalue given in hexadecimal/BCD-code */
int RUN = 1;
#define TIMER1 ( (unsigned int *) 0x920 )
#define PERIOD (49999)
/* Define addresses etc for de2_pio_keys4 */
volatile int * const de2_pio_keys4_base = (volatile int *) 0x840;
volatile int * const de2_pio_keys4_intmask = (volatile int *) 0x848;
volatile int * const de2_pio_keys4_edgecap = (volatile int *) 0x84c;
const int de2_pio_keys4_intindex = 2;
const int de2_pio_keys4_irqbit = 1 << 2;
/* Define address for de2_pio_hex_low28 */
volatile int * de2_pio_hex_low28 = (volatile int *) 0x9f0;
/*
* The n2_fatal_error function is called for unexpected
* conditions which most likely indicate a programming error
* somewhere in this file. The function prints "FATAL ERROR"
* using out_char_uart_0, lights an "Err" pattern on the
* seven-segment display, and then enters an infinite loop.
*/
void n2_fatal_error() {
/* Define the pattern to be sent to the seven-segment display. */
#define N2_FATAL_ERROR_HEX_PATTERN ( 0xcbd7ff )
/* Define error message text to be printed. */
static const char n2_fatal_error_text[] = "FATAL ERROR";
/* Define pointer for pointing into the error message text. */
register const char * cp = n2_fatal_error_text;
/* Send pattern to seven-segment display. */
*de2_pio_hex_low28 = N2_FATAL_ERROR_HEX_PATTERN;
/* Print the error message. */
while (*cp) {
//out_char_uart_0( *cp );
cp = cp + 1;
}
/* Stop and wait forever. */
while (1)
;
}
/*
* Interrupt handler for de2_pio_keys4.
* The parameters are ignored here, but are
* required for correct compilation.
* The type alt_u32 is an Altera-defined
* unsigned integer type.
*
* To help debugging interruptible interrupt-handlers,
* this handler delays a long while when a key is pressed.
* However, there is no delay when the key is released.
*
* We keep a software copy of the LED value, since
* the parallel output ports are not program-readable.
*
* Example: we send out the value 1 on de2_pio_keys4,
* by executing *DE2_PIO_KEYS4_BASE = 1;
* Then we try to read the port by executing
* int test_val = *DE2_PIO_KEYS4_BASE; // WRONG
* The value of test_val is now undefined.
* The port returns some bits which are not related
* to the value we have written.
*
* The software copy of the LED value
* for this interrupt handler
* is the global variable myleds, defined above.
*/
void irq_handler_keys(void * context, alt_u32 irqnum) {
alt_u32 save_value;
save_value = alt_irq_interruptible(de2_pio_keys4_intindex);
/* Read edge capture register of the de2_pio_keys4 device. */
int edges = *de2_pio_keys4_edgecap;
*de2_pio_keys4_edgecap = 0;
/* If action on KEY0 */
if (edges & 1) {
/* If KEY0 is pressed now */
if ((*de2_pio_keys4_base & 1) == 0) {
if (RUN == 0) {
RUN = 1;
} else {
RUN = 0;
}
}
/* If KEY0 is released now */
else if ((*de2_pio_keys4_base & 1) != 0) {
}
alt_irq_non_interruptible(save_value);
} else if (edges & 2) {
/* If KEY1 is pressed now */
if ((*de2_pio_keys4_base & 2) == 0) {
tick(&timeloc);
puttime(&timeloc);
puthex(timeloc);
}
/* If KEY1 is released now */
else if ((*de2_pio_keys4_base & 2) != 0) {
}
alt_irq_non_interruptible(save_value);
}
else if (edges & 4) {
/* If KEY2 is pressed now */
if ((*de2_pio_keys4_base & 4) == 0) {
timeloc = 0x0;
puttime(&timeloc);
puthex(timeloc);
}
/* If KEY2 is released now */
else if ((*de2_pio_keys4_base & 4) != 0) {
}
alt_irq_non_interruptible(save_value);
}
else if (edges & 8) {
/* If KEY3 is pressed now */
if ((*de2_pio_keys4_base & 8) == 0) {
timeloc = 0x5957;
puttime(&timeloc);
puthex(timeloc);
}
/* If KEY3 is released now */
else if ((*de2_pio_keys4_base & 8) != 0) {
}
alt_irq_non_interruptible(save_value);
}
}
/*
* Initialize de2_pio_keys4 for interrupts.
*/
void keysinit_int(void) {
/* Declare a temporary for checking return values
* from system-calls and library functions. */
register int ret_val_check;
/* Allow interrupts */
*de2_pio_keys4_intmask = 15;
/* Set up Altera's interrupt wrapper for
* interrupts from the de2_pio_keys4 device.
* The function alt_irq_register will enable
* interrupts from de2_pio_keys4.
* Return value is zero for success,
* nonzero for failure. */
ret_val_check = alt_irq_register(de2_pio_keys4_intindex, NULL_POINTER,
irq_handler_keys);
/* If there was an error, terminate the program. */
if (ret_val_check != 0)
n2_fatal_error();
}
int main() {
/* Remove unwanted interrupts.
* initfix_int is supplied by KTH.
* A nonzero return value indicates failure. */
if (initfix_int() != 0)
n2_fatal_error();
keysinit_int();
int counter = 0;
while (1) {
delay(1);
++counter;
if (counter % 1000 == 0) {
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_REDLED18_BASE, timeloc);
if (RUN == 1) {
tick(&timeloc);
puttime(&timeloc);
puthex(timeloc);
}
}
}
return 0;
}
int hex7seg(int digit) {
int trantab[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00,
0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e };
register int tmp = digit & 0xf;
return (trantab[tmp]);
}
void puthex(int inval) {
unsigned int hexresult;
hexresult = hex7seg(inval);
hexresult = hexresult | (hex7seg(inval >> 4) << 7);
hexresult = hexresult | (hex7seg(inval >> 8) << 14);
hexresult = hexresult | (hex7seg(inval >> 12) << 21);
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_HEX_LOW28_BASE, hexresult);
}发布于 2013-09-11 13:51:46
中断处理程序看起来有点冗长。有太多的评论,其中大部分是“噪音”(它们的贡献很小,在其他地方也是正确的),还有很多空白处(键控检测)。这是一个简化的版本,如果ISR:
void irq_handler_keys(void *context, alt_u32 irqnum)
{
const alt_u32 save_value = alt_irq_interruptible(irqnum);
const unsigned edges = *de2_pio_keys4_edgecap;
const unsigned keys = ~*de2_pio_keys4_base; // inverted
*de2_pio_keys4_edgecap = 0;
if (edges & PIO_KEYS4_TICK & keys) {
tick(&timeloc);
puttime(&timeloc);
puthex(timeloc);
} else if (edges & PIO_KEYS4_RUN & keys) {
RUN ^= 1;
} else if (edges & PIO_KEYS4_ZERO & keys) {
timeloc = ZERO_TIME;
puttime(&timeloc);
puthex(timeloc);
} else if (edges & PIO_KEYS4_RESET & keys) {
timeloc = INITIAL_TIME;
puttime(&timeloc);
puthex(timeloc);
}
alt_irq_non_interruptible(save_value);
}这些变化是明确的,但我会仔细研究一下。
alt_irq_interruptible的调用需要通过一个对alt_irq_non_interruptible的调用来平衡,而不是四个。对我来说,传递irqnum似乎比传递您假定的中断号更符合逻辑。unsigned值而不是int值(例如不能添加它们),键寄存器只需要在函数开始时读取。注意,RUN和timeloc应该是volatile。
https://codereview.stackexchange.com/questions/31080
复制相似问题