One uses a subroutine because it's reusable. Call if from anywhere, it picks up from the point of call. When the call instruction is executed, the FOLLOWING instruction is put onto the stack and the ip is set to the address of the subroutine. When the subroutine hits the return, the address on the stack is popped into the ip, and off you go, right where you left off. The thing is, you can't screw up the stack. You can use it in the subroutine, but you have to clean it up before the return. Else, you'll pop some data or register contents of something that you've saved on the stack, and the processor will think that junk is the address to return to.
A branch or jump is merely selecting a new path for the execution to follow. A subroutine is a timeout to do something, then pick up where you left off. You need to get that difference into your head.