Because you think on it like pins and not ports. If you connected an 8-bit bus to a port, would you read it bit by bit?
No, you read the port register in a single read instruction.
You have simple macros/defines to access and configure single pins. Your code can be easily reconfigurable by just using defines:
#define Toggle(x) x^=1;
#define LED LATA1
#define LED_TRIS TRISA1
#define LED2 LATA2
#define LED2_TRIS TRISA2
#define BUTTON RA3
#define BUTTON_TRIS TRISA3
void init(void){
LED_PIN=LOW;
LED_TRIS=OUTPUT;
LED2_PIN=LOW;
LED2_TRIS=OUTPUT;
BUTTON_TRIS=INPUT;
}
void main(void){
init();
while(1){
LED=BUTTON;
Toggle(LED2);
if(BUTTON){
button_detected();
}
}
}
For a parallel port, yes, you're correct, it would be stupid to access it as individual pins. That's one of the exception cases.
For your style of defining pins, something similar was what I tried many decades ago. But there were three problems.
First, the "=" operator works fine for Microchip, but isn't compatible across the board with all MCUs. Defining a simple macro to look like a function, but does the same thing, works as a good alternative.
Second, initializing a pin, even if it's done in discrete steps, is often thought of in terms of one atomic operation. If you're setting a pin as an output pin, you'd better be setting the level at the same time (preferably right before setting it as an output). If not, you'll easily get unwanted results momentarily on the pins while it's being initialized. Making it as a function/macro init function for the pin allows this to be done without thinking about it. Of course, a good firmware engineer will code it in the correct order, as you did in your example, but sometimes we all make mistakes and forget things. A well designed macro can handle all of this while generating the same final code, but just making the sure the correct sequence is done, while also making the code more readable.
Third, when I'm developing/debugging, and testing pins with a scope or other test equipment, I reference my code and the schematic to find where I need to probe. I find it easy if I just have my board header file open, see the net name and pin number, and can then also search for that net name to find all occurrences of where I'm using it, so that I can change code easily. I rarely need to know the port number. Pin number (for probing or referencing on the schematic) and net name (for searching my code or also for referencing the schematic) are what I need. If I happen to need to know the port number, I can also call that up using the header file I made for the MCU part number defines, or via the MCU datasheet.
A board header file can easily be scanned to see all the interfaces organized, which pin numbers are being used for each pin of the interface, which levels are defined for those pins, etc. It just makes it all nicely organized from the firmware point-of-view. The more experienced I get as a firmware engineer, the more I realize how keeping things neat and organized like that really help with efficiency and also help greatly when returning to a project after not having worked on it for a number of years, or when a bunch of different projects are being done simultaneously and it's easy to forget details of one particular project. A quick glance at the board header file, and you easily see all the interfaces you're using, along with some brief comments in the header file about each interface, and the mind is instantly refreshed about the details of that project and ready to dig into doing whatever needs to be done. If I'm talking to a hardware, QC, PCB, or other engineer about our project, I always refer to pins by their pin number and/or net name. In general everyday use in firmware, I just don't see the need for using port numbers in the forefront, especially regarding GPIO pins.
Having definitions such as "LED_TRIS" means you're limiting your thinking regarding names to just the Microchip (not even including Atmel) realm. If you're always going to use Microchip exclusively, it might be ok, but when your code is needed to be used across a broad spectrum of devices from various manufacturers, you may find that using functions/macros while define things in terms of functionality rather than specific vendor terminology makes the code much more portable and easier to understand. Even within Microchip, there's quirks in certain devices/families regarding initializing pins, as I recall. It's very easy to forget about those quirks, or fail to recall that those quirks are applicable to the part you're working on.
I could go on and on about what I think is well-structured/organized MCU programming, but then in the end it's just my personal opinion, and I'm in no way want to force my opinion on anyone else. I do though think the MCU world is very lacking in teaching good techniques. There's countless books teaching good general programming techniques, but when it comes to MCU programming, and accessing hardware/peripherals, almost all the materials concentrate way too much on specific MCU coding for the one MCU they're teaching about, and very little on making the code portable and thinking beyond that particular MCU.